プログラミング言語「Python」で制作 Part108 | Photoshop CC Tutorials

今回はプログラミング言語の「Python」を使って作成しました。

 

下記の本のサンプルの「分子運動のシミュレーション」をPygameで動くように移植しました。

 

下画像の式で動いています。

 

■ プログラム

import traceback

try:
    import sys
    import math
    import random
    import pygame
    from pygame.locals import QUIT, KEYDOWN, K_LEFT, K_RIGHT, K_SPACE, Rect

    #-----------------------------------------------------------
    # クラス定義
    #-----------------------------------------------------------
    class Block:
        """ ボールオブジェクト """
        def __init__(self, col, rect, W):
            #--- 初期値設定 ---
            self.col = col
            self.rect = rect
            self.W = W
            self.x = rect.x
            self.y = rect.y

        def move(self):
            """ ボールを動かす """
            self.rect = Rect(self.x,self.y, self.W, self.W)

        def draw(self):
            """ ボールを描画する """
            pygame.draw.ellipse(SURFACE, self.col, self.rect)

    def array(N1, N2=0, N3=0):
        if N2 == 0 and N3==0: return [0 for i in range(N1)]
        elif N3 == 0: return [[0 for i in range(N2)] for j in range(N1)]
        else: return [[[0 for i in range(N3)] for j in range(N2)]
                      for k in range(N1)]
    def genMole():
        global N, R
        for i in range(N):
            R[0][i][0] = random.random() * (Xmax - 2.0) + 1.0
            R[0][i][1] = random.random() * (Ymax - 2.0) + 1.0

    Xmax = 10; Ymax = 10; DispR = 20
    EPSI = 1.0; SIGMA = 1;MG = 1
    N=40                               # 分子の数
    DT=0.05                            # 時間刻み
    timerInt=10                        # 表示時間間隔
    R=array(2,N,2); F=array(N,2)       # R:位置,F:力
    V=array(2,N,2); Bname=array(N)     # V:速度, Bname:表示円形
    E1 = -48 * EPSI * pow(SIGMA,13)    # 計算用係数
    E2 = 24 * EPSI * pow(SIGMA, 7)
    alfa= 0.1                          # alfa = M/(3kT) とみなす(M: 分子質量合計)
    ID1 = 0; ID2 = 1                   # 実行制御用
    Nup=0;Vup=0;Nlf=0; Vlf=0           #衝突回数と衝突速度の絶対値合計
    Nbt=0;Vbt=0;Nrt=0; Vrt=0
    sCtr=0                             #シミュレーション回数

    #--------------------------------------------------------------
    # 画面上の分子の生成
    #--------------------------------------------------------------
    def genMono(canvas, X0, Y0,R):
        return canvas.create_oval(X0-R,Y0-R, X0+R, Y0+R,fill="red")

    def init():             #■初期設定
        global N, F, V,Bname,DispR
        for i in range(N):
            Bname[i] = Block((random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), Rect(random.randint(0, 150), random.randint(-150, 0), DispR, DispR), DispR)

    #--------------------------------------------------------------
    # 画面上の分子の表示
    #--------------------------------------------------------------
    def dsp(ID1):
        global N, canvas, R, Bname, DispR
        RD=DispR
        for i in range(N):
            X = R[ID1][i][0]*20
            Y = R[ID1][i][1]*20
            """ ボールを描画する """
            Bname[i].rect.x = X-RD
            Bname[i].rect.y = Y-RD
            Bname[i].rect.w = RD
            Bname[i].rect.h = RD
            pygame.draw.ellipse(SURFACE, Bname[i].col, Bname[i].rect)

    def force(ID1):         #■力の計算
        global N, F, R, alfa
        for i in range(N):
            F[i][0] = 0; F[i][1] = 0
            for j in range(N):
                if i != j :
                    dX = R[ID1][j][0] - R[ID1][i][0]
                    dY = R[ID1][j][1] - R[ID1][i][1]
                    DR = math.sqrt(dX * dX + dY * dY)
                    if DR < 1 : DR = 1
                    FF = E1 / math.pow(DR,13) + E2 / math.pow(DR,7)
                    F[i][0] = F[i][0] + FF * dX / DR
                    F[i][1] = F[i][1] + FF * dY / DR

    def velocity(ID1,ID2):  #■速度の計算
        global N, F, V,MG
        for i in range(N):
            V[ID2][i][0] = V[ID1][i][0] + DT * F[i][0]/ MG
            V[ID2][i][1] = V[ID1][i][1] + DT * F[i][1]/ MG
        T = 0 # 温度境界条件
        for i in range(N):
            VX = V[ID2][i][0]; VY = V[ID2][i][1]
            T += VX * VX + VY * VY
        T = math.sqrt(T)* alfa
        if T > 0.00001:
            for i in range(N):
                V[ID2][i][0] /= T; V[ID2][i][1] /= T

    def place(ID1,ID2):     #■位置の計算
        global N, V, X
        for i in range(N):
            R[ID2][i][0] = R[ID1][i][0] + DT * V[ID2][i][0]
            R[ID2][i][1] = R[ID1][i][1] + DT * V[ID2][i][1]

    def wallHit(ID2):#■壁への衝突
        global Nup,Vup,Nlf, Vlf, Nbt, Vbt,Nrt, Vrt
        for i in range(N):
            if R[ID2][i][0] < (0.5 * SIGMA):
                R[ID2][i][0] = 0.5 * SIGMA
                AV=abs(V[ID2][i][0])
                V[ID2][i][0] = AV; Nlf+=1; Vlf+=AV
            if R[ID2][i][0] > (Xmax - 0.5 * SIGMA):
                R[ID2][i][0] = Xmax - 0.5 * SIGMA
                AV=abs(V[ID2][i][0])
                V[ID2][i][0] = -AV; Nrt+=1; Vrt+=AV
            if R[ID2][i][1] < (0.5 * SIGMA):
                R[ID2][i][1] = 0.5 * SIGMA
                AV=abs(V[ID2][i][1])
                V[ID2][i][1] = AV; Nup+=1; Vup+=AV
            if R[ID2][i][1] > (Ymax - 0.5 * SIGMA):
                R[ID2][i][1] = Ymax - 0.5 * SIGMA
                AV=abs(V[ID2][i][1])
                V[ID2][i][1] = -AV; Nbt+=1; Vbt+=AV

    #--------------------------------------------------------------
    # 画面上の分子のシミュレーション
    #--------------------------------------------------------------
    def simulate(ID1, ID2):
        global sCtr,Vup,Vlf,Vbt, Vrt, root
        dsp(ID1); force(ID1); velocity(ID1,ID2)
        place(ID1,ID2); wallHit(ID2)
        sCtr+=1;
        #print("%d, %7.4f, %7.4f, %7.4f, %7.4f" % (sCtr, Vup/sCtr,Vbt/sCtr, Vlf/sCtr,Vrt/sCtr))

    #--------------------------------------------------------------
    # メイン処理
    #--------------------------------------------------------------
    
    init(); genMole();ID1=0
    ID1=0

    # Pygame初期設定
    pygame.init()
    SURFACE = pygame.display.set_mode((200, 200))
    FPSCLOCK = pygame.time.Clock()
    fps = 60
    #--------------------------------------------------------------
    # ループ処理
    #--------------------------------------------------------------
    while True:
        #-----------------------------------------------------------
        # 描画処理
        #-----------------------------------------------------------
        SURFACE.fill((0, 0, 0))

        ID2=1-ID1;
        simulate(ID1,ID2)
        ID1=ID2

        pygame.display.update()
        FPSCLOCK.tick(fps)

except Exception as e:
    print("エラー情報\n" + traceback.format_exc())

input()

 

■ 参考書

「Python 3.6 による 力学シミュレーション 第4巻: 分子」

 

■ ゲーム用ライブラリ

「Pygame」

 

■ プログラミング言語

「Python」