マンデルブログ

主にPythonのことを書いていきます。

PythonでDLAを描く(1)

DLAって何ぞや??

https://upload.wikimedia.org/wikipedia/commons/3/3d/Of7_p0001_15h.jpg

DLAとは、ブラウン運動する粒子が核にくっついていくことでできていく枝分かれした結晶のことです。
拡散律速凝集(Diffusion Limited Aggregation)の略です。DNAじゃないよ。

DLAができる現象はいくつかあるのですが、詳しくは拡散律速凝集 - Wikipediaで。

前に一度、C言語でDLAのプログラムを書こうとしたのですが、そのときは挫折してしまいました。
今回はそのリベンジを兼ねてPythonで作っていきます。何回かにわけて記事にしようと思います。


基本的なルール

  1. 場の中心に核(seed)となる粒子が置かれる。
  2. 他の粒子は場の境界線に置かれ、ランダムウォークをする。
  3. 粒子が核に触れると核とくっつき、その粒子も核となる。
  4. 核が場の境界に達すると終了する。

今日やること

今日は細部まで作りこむ前に、粒子がランダムウォークをして核にくっつくという部分を作りたいと思います。
長めになるのでSpyderを使用しました。

import random
import numpy as np
import matplotlib.pyplot as plt

class Diffusion():
    def __init__(self):
        self.seed = [[0,0]]
        
    def randomwalk(self,x,y):
        a = random.choice([[1,0],[-1,0],[0,1],[0,-1]])
        return x+a[0],y+a[1]
    
    def contact(self,x,y):
        for i,j in self.seed:
            if (x-i==0 and abs(y-j)==1) or (abs(x-i)==1 and y-j==0):
                self.seed.append([x,y])
                return False
        return True
    
    def ini_posi(self):
        ini = [[i,j] for i in range(-10,11) for j in range(-10,11) if abs(i)+abs(j) == 15]
        return random.choice(ini)
    
    def out_range(self,x,y):
        out_posi = [[i,j] for i in range(-20,21) for j in range(-20,21) if abs(i)+abs(j) == 30]
        for i,j in out_posi:
            if x==i and y==j:
                return False
        return True
    
    def diffusion(self):
        start = self.ini_posi()
        x,y = self.randomwalk(start[0],start[1])
        
        flag = True
        while flag:
            x,y = self.randomwalk(x,y)
            flag = self.contact(x,y)
            flag = self.out_range(x,y)
            
            if abs(x)+abs(y)>15:
                flag = False
        
        print(self.seed)
        
d = Diffusion()
flag = True
while flag:
    d.diffusion()
    
    if len(d.seed)>10:
        break
    
plt.plot(*np.array(d.seed).T,"o")
plt.savefig("DLA_test.png", bbox_inches="tight", pad_inches=0.0)

計算時間短縮のため、粒子を核の近くから発射するようにしています。
また粒子が核から離れすぎるとループを終了して、新しく粒子を発射しなおすようにもしています。

で、できたのがこちらです。
f:id:woodhero0908:20180622001154p:plain

範囲を狭くしているのでまだまだ枝は細かくないですね。
次回はもっと範囲を大きくするために、粒子の発射位置を更新するプログラムを加えていきたいと思います。

6/23追記

後から気づいたのですが、このプログラム致命的なミスがあります。
どこだかわかりますか?
woodhero2357.hatenablog.com