带电粒子在电磁场中的运动的计算机模拟

样例

样例1

样例1
模型描述:在一个布满整个空间、垂直纸面向下的匀强磁场中,两个等质量、带等量电荷但电荷量相反的两个带电粒子由静止释放。
指令:
md1.txt:

adm
-7500
True
N
-10000000
-10000000
10000000
-10000000
10000000
10000000
-10000000
10000000
end
adb
9.5
-9
1
0
0
0.0003
adb
9.5
9
1
0
0
-0.0003
s
10
0.01
1
Y

然后输入python SMCPEF.py md1 <md1.txt

样例2


模型描述:一个带电粒子在一个布满整个空间、沿纸面向下的匀强电场中作类斜抛运动。

样例3


模型描述:一个带电粒子在一个最普通的跑道形回旋加速器中的运动
指令:
md3.txt

adb
0
-9
1
0
0
1
ade
3
0
-1<x<1 and -9.1<y<-8.9
N
-1
-9.1
1
-9.1
1
-8.9
-1
-8.9
end
adm
-1
x>=1
N
1
-100000
100000
-100000
100000
100000
1
100000
end
adm
-1
x<=-1
N
-1
100000
-100000
100000
-100000
-100000
-1
-100000
end
s
10
0.001
1
Y

然后输入python SMCPEF.py md3 <md3.txt

源代码

SMCPEF.py

import os
import sys
import matplotlib.pyplot as plt
import time
import math
import numpy as np
import cv2
from math import sin,cos,tan,pi,sqrt


if len(sys.argv)==1:
    while True:
        s=input("请输入项目名称(不能有空格) >>>")
        os.system("python "+sys.argv[0]+" "+s)
MyName=sys.argv[1]
EBalls=[]
FMags=[]
FEles=[]
Boards=[]
Reflcs=[]
Geners=[]
ori_pics=[]
CameraMove=False
Lx=-10
Ly=10
Width=20
#----------------------------------------------
e_k=8987551787
TC=0
plt.figure(figsize=(10.24,10.24))
#----------------------------------------------
class Pic_t:
    def __init__(self,ti):
        self.time=ti
        self.obj=[]
    def add_object(self,o):
        self.obj.append(o)

class Vector:
    def __init__(self,x,y):
        self.x=x
        self.y=y
def Add(A,B):
    return Vector(A.x+B.x,A.y+B.y)
def Minus(A,B):
    return Vector(A.x-B.x,A.y-B.y)
def NMt(k,A):
    return Vector(A.x*k,A.y*k)

class Ball:
    def __init__(self,name,X,Y,m,vx,vy,q):
        self.name=name
        self.X=X
        self.Y=Y
        self.m=m
        self.vx=vx
        self.vy=vy
        self.q=q
        self.alive=1
        
    def Draw_Bound(self):
        pass
    def Force(self,t,bb):
        global e_k
        A=Vector(self.X,self.Y)
        B=Vector(bb.X,bb.Y)
        t=-e_k*self.q*bb.q
        C=Minus(A,B)
        FS=t/(C.x*C.x+C.y*C.y)
        L=math.sqrt(C.x*C.x+C.y*C.y)
        C=NMt(FS/L,C)
        return C

class Mag:
    def __init__(self,name):
        self.name=name
    def Draw_Bound(self):
        pass
    def B(self,t,x,y):
        pass
    def inm(self,x,y):
        pass
    def Force(self,t,ball):# F=qvB
        if not self.inm(ball.X,ball.Y):
            return Vector(0,0)
        b=self.B(t,ball.X,ball.Y) # B=(0,0,b) v=(vx,vy,0) (vy*b,-vx*b,0)
        return NMt(ball.q,Vector(ball.vy*b,-ball.vx*b))

class Ele():
    def __init__(self,name):
        self.name=name
    def Draw_Bound(self):
        pass
    def E(self,t,x,y):
        pass
    def ine(self,x,y):
        pass
    def Force(self,t,ball):
        if not self.ine(ball.X,ball.Y):
            return Vector(0,0)
        v=self.E(t,ball.X,ball.Y)
        v=NMt(ball.q,v)
        return v

class Board:
    def __init__(self,name,a,b,c,d):
        self.name=name
        self.va=a
        self.vb=b
        self.vc=c
        self.lm=d
    def Draw_Bound(self):
        pass
    def itr(self,x1,y1,x2,y2):
        pass
    def idv(self,x,y):
        pass
    def bounce(self,ball):
        pass

class LBoard(Board):
    def __init__(self,name,A,B,C,L):
        super(Board,self).__init__(name,A,B,C,L)
    def Draw_Bound(self):
        pass
    def itr(self,x1,y1,x2,y2):
        pass
    def idv(self,x,y):
        pass
    def bounce(self,ball):
        pass

class CBoard(Board):
    def __init__(self,name,x,y,R,L):
        super(Board,self).__init__(name,x,y,R,L)
    def Draw_Bound(self):
        pass
    def itr(self,x1,y1,x2,y2):
        pass
    def idv(self,x,y):
        pass
    def bounce(self,ball):
        pass
        
def Engine():# 物理引擎
    global TC,TR
    #print(len(FMags))
    while TC<=TR:
        #--------------------------
        dt=Tik(TC)
        totBall=len(EBalls)
        for i in range(totBall):
            dx=NMt(dt,Vector(EBalls[i].vx,EBalls[i].vy))
            #---------------------------判断碰撞
            #---------------------------
            EBalls[i].X+=dx.x
            EBalls[i].Y+=dx.y
            F=Vector(0,0)
            for j in range(totBall):
                if i!=j:
                    F=Add(F,EBalls[j].Force(TC,EBalls[i]))
            for j in FMags:
                F=Add(F,j.Force(TC,EBalls[i]))
                #print(F.x,F.y)
            for j in FEles:
                F=Add(F,j.Force(TC,EBalls[i]))
            dv=NMt(dt/EBalls[i].m,F)
            EBalls[i].vx+=dv.x
            EBalls[i].vy+=dv.y
            #print(EBalls[i].name,EBalls[i].X,EBalls[i].Y)
        #--------------------------
        nP=Pic_t(TC)
        for i in EBalls:
            nP.add_object(["Ball",i.name,i.X,i.Y])
        #print("length",len(nP.obj))
        ori_pics.append(nP)
        TC=TC+dt
def NeedMove(point):
    global Lx,Ly,Width
    tot=len(ori_pics[point].obj)
    for i in range(tot):
        if ori_pics[point].obj[i][0]=="Ball":
            if Lx<=ori_pics[point].obj[i][2]<=Lx+Width and Ly-Width<=ori_pics[point].obj[i][3]<=Ly:
                pass
            else:
                #print("2!!!",item.X,item.Y)
                return 2
    for i in range(tot):
        if ori_pics[point].obj[i][0]=="Ball":
            for j in range(tot):
                if i!=j and ori_pics[point].obj[j][0]=="Ball":
                    dx=ori_pics[point].obj[i][2]-ori_pics[point].obj[j][2]
                    dy=ori_pics[point].obj[i][3]-ori_pics[point].obj[j][3]
                    if sqrt(dx*dx+dy*dy)<=0.01*Width:
                        print("1!!!")
                        return 1
    return 0

def PicBuilder():#20帧的视频
    global BS,ori_pics,Lx,Ly,Width
    realtimepertik=0.05*BS
    point=0
    tikid=0
    while point<len(ori_pics):
        Rtime=realtimepertik*tikid
        while point<len(ori_pics):
            if point+1<len(ori_pics) and ori_pics[point+1].time<=Rtime:
                point+=1
            else:
                break
        if point==len(ori_pics)-1:
            break
        #开始画
        if CameraMove==True:
            st=NeedMove(point)
            if st!=0:
                Minx=10.0**20.0
                Maxx=-Minx
                Miny=Minx
                Maxy=-Minx
                for item in ori_pics[point].obj:
                    if item[0]!="Ball":
                        continue
                    Minx=min(Minx,item[2])
                    Maxx=max(Maxx,item[2])
                    Miny=min(Miny,item[3])
                    Maxy=max(Maxy,item[3])
                ttt=max(Maxx-Minx,Maxy-Miny)
                if ttt==0:
                    ttt=19/2
                Width=int(2*ttt+1)
                Lx=Minx-0.25*Width
                Ly=Maxy+0.25*Width
            else:
                pass
        #print([Lx,Lx+Width,Ly-Width,Ly])
        plt.axis([Lx,Lx+Width,Ly-Width,Ly])
        plt.rcParams['font.sans-serif']=['SimHei']
        plt.rcParams['axes.unicode_minus']=False
        #plt.scatter(x_values, y_values, s=100)
        #print("size:",len(ori_pics[point].obj))
        for item in FMags:
            item.Draw_Bound()
        for item in FEles:
            item.Draw_Bound()
        for item in ori_pics[point].obj:
            if item[0]=="Ball":
                plt.scatter(item[2],item[3],color="black")
                #print(item[2],item[3])
        plt.savefig("tmp/"+str(tikid)+".png")
        plt.clf()
        tikid=tikid+1
    return tikid-1

def VideoBuilder(tot):
    size = (1024,1024)
    videowrite = cv2.VideoWriter(MyName+'.mp4',cv2.VideoWriter_fourcc('M', 'P', '4', 'V'),20,size)
    img_array=[]
    for filename in [r'tmp\\\{0}.png'.format(i) for i in range(tot+1)]:
        img = cv2.imread(filename)
        if img is None:
            print(filename + " is error!")
            continue
        img_array.append(img)
    for i in range(tot+1):
        videowrite.write(img_array[i])
    videowrite.release()
    
def Render():
    a=PicBuilder()
    print("照片生成完毕,正在合成视频")
    VideoBuilder(a)

#--------------------------------------------------------
TR,BS,Tik_time=0,0,0
block_len=20
def Tik(T):
    return Tik_time

def G1(T):
    gtime=2
    if T>=gtime:
        pass

Geners.append(G1)
Geners[0](TC)
    
def Quit():
    quit(0)
def Adv():
    os.system("copy "+sys.argv[0]+" 高级版本.py")
    input("请按打开 高级版本.py 自行编辑 按Enter退出当前会话")
def Adb():
    global EBalls
    #def __init__(self,name,X,Y,m,vx,vy,q):
    name=""#input("请输入小球名称")
    X=float(input("请输入小球X坐标"))
    Y=float(input("请输入小球Y坐标"))
    m=float(input("请输入小球质量"))
    vx=float(input("请输入小球X方向分速度"))
    vy=float(input("请输入小球Y方向分速度"))
    q=float(input("请输入小球电荷量"))
    EBalls.append(Ball(name,X,Y,m,vx,vy,q))

class EF1(Ele):
    def __init__(self,name,Ex,Ey,inf,X,Y):
        Ele.__init__(self,name)
        self.name=name
        self.Ex=Ex
        self.Ey=Ey
        self.inf=inf
        self.X=X
        self.Y=Y
        
    def Draw_Bound(self):
         plt.fill(self.X,self.Y, 'r')
         
    def E(self,t,x,y):
        t=t
        x=x
        y=y
        ex=eval(self.Ex)
        ey=eval(self.Ey)
        return Vector(ex,ey)
    def ine(self,x,y):
        x=x
        y=y
        return eval(self.inf)
def Ade():
    name=""#input("请输入电场名称")
    Ex=input("请输入点(x,y)处在t时刻场强的X分量(用无赋值的单行python表达式)")
    Ey=input("请输入点(x,y)处在t时刻场强的Y分量(用无赋值的单行python表达式)")
    inf=input("请输入点(x,y)是否位于电场内部的判别式")
    s=input("是否为圆形? Y/N ")
    X=[]
    Y=[]
    if s=="Y":
        x=float(input("X"))
        y=float(input("Y"))
        r=float(input("R"))
        for i in range(1000):
            theta=2*pi*i/1000
            X.append(x+r*cos(theta))
            Y.append(y+r*sin(theta))
    else:
        print("接下来请依次逆时针输入边界坐标,无需重复输入第一个点,结束时输入end")
        tot=0
        while True:
            tot+=1
            s=input("第"+str(tot)+"个的X坐标")
            if s=="end":
                break
            X.append(float(s))
            s=input("第"+str(tot)+"个的Y坐标")
            if s=="end":
                break
            Y.append(float(s))
    FEles.append(EF1(name,Ex,Ey,inf,X,Y))

class MF1(Mag):
    def __init__(self,name,Bs,inf,X,Y):
        Mag.__init__(self,name)
        self.name=name
        self.Bs=Bs
        self.inf=inf
        self.X=X
        self.Y=Y
    def Draw_Bound(self):
        plt.fill(self.X,self.Y, 'blue')
    def B(self,t,x,y):
        return eval(self.Bs)
    def inm(self,x,y):
        return eval(self.inf)
def Adm():
    name=""#input("请输入磁场名称")
    B=input("请输入点(x,y)处在t时刻场强(正为指向纸外)(用无赋值的单行python表达式)")
    inf=input("请输入点(x,y)是否位于磁场内部的判别式")
    s=input("是否为圆形? Y/N ")
    X=[]
    Y=[]
    if s=="Y":
        x=float(input("X"))
        y=float(input("Y"))
        r=float(input("R"))
        for i in range(1000):
            theta=2*pi*i/1000
            X.append(x+r*cos(theta))
            Y.append(y+r*sin(theta))
    else:
        print("接下来请依次逆时针输入边界坐标,无需重复输入第一个点,结束时输入end")
        tot=0
        while True:
            tot+=1
            s=input("第"+str(tot)+"个的X坐标")
            if s=="end":
                break
            X.append(float(s))
            s=input("第"+str(tot)+"个的Y坐标")
            if s=="end":
                break
            Y.append(float(s))
    FMags.append(MF1(name,B,inf,X,Y))
def Start():
    global TR,Tik_time,BS,CameraMove,Lx,Ly,Width
    TR=float(input("渲染总时长"))
    Tik_time=float(input("单步时间间隔"))
    BS=float(input("视频倍速"))
    cm=input("是否打开摄像头自动移动?(否则将为恒定范围)Y/N")
    if cm=='Y':
        CameraMove=True
    else:
        Lx=float(input("请输入左上角X坐标"))
        Ly=float(input("请输入左上角Y坐标"))
        Width=float(input("请输入视野宽度"))
    Engine()
    print("物理运算完毕,开始渲染")
    print("长度:",len(ori_pics))
    Render()
    input("合成完成,请按Enter推出并查看"+MyName+".mp4")
    Quit()
Menu={"adv":Adv,"s":Start,"adb":Adb,"ade":Ade,"adm":Adm,"q":Quit}
while True:
    s=input("""请输入命令:
adv 进入高级模式
s 开始模拟
adb 增加一个带电小球
ade 增加一个电场
adm 增加一个磁场
q 退出
>>> """)
    if s in ["adv","s","adb","ade","adm","q"]:
        Menu[s]()
posted @ 2022-02-28 23:07  happyZYM  阅读(21)  评论(0编辑  收藏  举报