Python What Could be Causing Discrepancies in My Python Gas Simulation?

AI Thread Summary
The Python gas simulation using Pygame is experiencing discrepancies in calculated physical parameters like pressure, temperature, and volume compared to expected gas laws. The simulation operates in 2D, which alters the relationships between these parameters, particularly affecting the mean free path and pressure calculations. Users noted that the mean free path should be proportional to 1/R instead of 1/R^2 in a 2D context. The code provided lacks certain calculations for temperature and pressure, which are crucial for accuracy. Despite adjustments, the kinetic energy is not fully conserved, suggesting potential issues in the collision handling or energy transfer calculations.
leibo
Messages
11
Reaction score
1
Hello.

I wrote a simple gas simulation in python, with pygame. In the simulation the atoms collide elastic collisions with each other and with the walls. Although the simulation does run and the collisions look realistic, when I try to calculate physical parameters like p,T,V,n and compare them to the gas law's there is no match. For example, when the radius is doubled the mean free path becomes smaller, but not in a factor of 2^2=4. the ratio PV/NT is not exactly constant and can be changed by a factor of 10, etc. I wonder what can be the problem? thank you.

this is the code:
Code:
from __future__ import division
import pygame, sys,pygame.mixer
import math
import pylab
import numpy as np
import time
import random
from pygame.locals import*
pygame.init()

"""basic variables"""
clock = pygame.time.Clock()
font1 = pygame.font.Font(None, 17)
edgeX,edgeY = 10,10
boxWidth,boxHeight = 950,680
size = width,height = 1000,700
centerX,centerY=int(width/2),int(height/2)
screen = pygame.display.set_mode(size)
x,y = width/2, height/2
radius = 3
number_of_atoms =200
position = []
v = []
color = []

"""set initial positions and velocities"""

for j in range(number_of_atoms):
    position.append([400+random.randint(-250,320),325+random.randint(-285,375),0])
    v.append([random.uniform(-5,5),random.uniform(-5,5)])
    m.append(1)
    color.append((0,0,255))
color[number_of_atoms-1]=((250,0,0))
for i in range(4):
 v.append([0,0])

def colission(a,v,b): # a - list of all atoms, v - list of all velocites (atom j has in position position[j] and travel with velocity v[j]), b - the atom we check for collisions
 for ball in a:
  if ball is not b:
   distanceX,distanceY = (b[0]-ball[0]),(b[1]-ball[1])
   distance = distanceX*distanceX + distanceY*distanceY
   if distance < 36: #radius=3,(2radius)**2=36
    ma,mb=1,1 #the mass of all atoms is 1
    i,j = a.index(ball),a.index(b)
    change = [-0.15*distanceX,-0.15*distanceY]

    Vax,Vay = v[i][0],v[i][1]
    Vbx,Vby = v[j][0],v[j][1]

    Angle =math.atan2(distanceY,distanceX) # math.acos((distanceX/distance))
    cos,sin = math.cos(Angle),math.sin(Angle)

    #changing coordiantes:
    vg,vh=[Vag,Vah],[Vbg,Vbh]=[Vax*cos+Vay*sin,Vay*cos-Vax*sin],[Vbx*cos+Vby*sin,Vby*cos-Vbx*sin]

    #after collision:
    Va2,Vb2=(2*mb*Vbg)/(ma+mb), (2*ma*Vag)/(ma+mb) #because ma=mb the term (ma-mb)*Vag or (mb-ma)*Vbg  cancels out

    v1,v2 = [Va2,Vah] , [Vb2,Vbh]
    #changing coordiantes again:
    sin = -sin
    v1,v2 =  [(Va2*cos+Vah*sin),Vah*cos-Va2*sin], [v2[0]*cos+v2[1]*sin,v2[1]*cos-v2[0]*sin]
    v[j],v[i]= v2,v1 #update velocites
    a[i][0],a[i][1]=a[i][0] + change[0], a[i][1] + change[1] #treating overlaps
    return()

"""the loop"""

while 1:
    screen.fill((0,0,0))

    mouseX,mouseY=pygame.mouse.get_pos()
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        pygame.quit()
        sys.exit()
     elif event.type == MOUSEBUTTONDOWN:
        if mouseY<edgeY+50 and mouseY>edgeY-50 and mouseX<edgeX+boxWidth and mouseX>edgeX-50:
         z=1
     elif event.type == MOUSEBUTTONUP:
        z=0
    if z==1:
        dy = mouseY-edgeY
        boxHeight = boxHeight-dy
        edgeY=mouseY

    pygame.draw.rect(screen, (200,100,0), (edgeX,edgeY,boxWidth,boxHeight),1)
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        sys.exit()

    for j in range(len(position[:number_of_atoms])):
        colission(position,v,position[j]) #check for collisions
        position[j][0]+=v[j][0] 
        position[j][1]+=v[j][1]

        """checking for collisions with the walls"""
        if position[j][0]+radius>edgeX+boxWidth:
         
         v[j][0]=-1*(v[j][0])
         position[j]=[(-radius+edgeX+boxWidth)-2,position[j][1],0]

        if position[j][0] - radius<edgeX:
         
         v[j][0]=-1*(v[j][0])
         position[j]=[radius+edgeX+2,position[j][1],0]

        if position[j][1]+radius>edgeY+boxHeight:
        
         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],(-radius+edgeY+boxHeight)-2,0]

        if position[j][1]-radius<edgeY:
       
         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],edgeY+2+radius,0]

    clock.tick(40)
    for i in range(len(position[:number_of_atoms])):
     circle = pygame.draw.circle(screen,color[i], (int(position[i][0]),int(position[i][1])),radius)
    pygame.display.flip()
 
Technology news on Phys.org
leibo said:
Hello.

I wrote a simple gas simulation in python, with pygame. In the simulation the atoms collide elastic collisions with each other and with the walls. Although the simulation does run and the collisions look realistic, when I try to calculate physical parameters like p,T,V,n and compare them to the gas law's there is no match. For example, when the radius is doubled the mean free path becomes smaller, but not in a factor of 2^2=4. the ratio PV/NT is not exactly constant and can be changed by a factor of 10, etc. I wonder what can be the problem? thank you.

Nice simulation leibo. It looks like it would be good for demonstration purposes. :smile:

I think one of the issues that you've got there is the fact that it's 2D instead of 3D like a real (or ideal) gas. I'm not an expert on this but just doing some quick calculations I think that in the 2D model you should still get PA = const * NT, (where here I've defined P as the force per unit length for the 2D case). Note also that area (A) replaces volume (V) in this case.

As for the mean free path, that's another calculation that you're going to have to make adjustments for in the 2D case versus the usual 3D case. Again I could be wrong, but my calculations suggest that the MFP should be proportional to 1/R (instead of 1/R^2) in this 2D case.

I couldn't see anywhere in your code where you were calculating any quantities such as temperature (rms velocity) or pressure. Since you say you're getting inconstant values for these quantities then I assume you must be calculating them somewhere. Was this code removed to make it more compact to post here?

BTW. I had to make a few small additions to your code to get it to run on my computer (maybe different versions of Python or Pygame). Just simple uninitialized variables. I had to add m=[] and z=0 to the initialization section. Not initializing "m" looks like an oversight, but "z" looks likes it's supposed to be initialized to either 0 or 1 somewhere within an if ... elif ... elif ... structure. I didn't fully trace the code to find where, but it must be getting through that block somehow without setting "z", so that also caused the program to crash on my computer. Anyway, putting "z=0" in the initialization section fixed the issue.
 
Here is a gas simulation using visual python.

gas-program
 
uart said:
Nice simulation leibo. It looks like it would be good for demonstration purposes. :smile:

I think one of the issues that you've got there is the fact that it's 2D instead of 3D like a real (or ideal) gas. I'm not an expert on this but just doing some quick calculations I think that in the 2D model you should still get PA = const * NT, (where here I've defined P as the force per unit length for the 2D case). Note also that area (A) replaces volume (V) in this case.

As for the mean free path, that's another calculation that you're going to have to make adjustments for in the 2D case versus the usual 3D case. Again I could be wrong, but my calculations suggest that the MFP should be proportional to 1/R (instead of 1/R^2) in this 2D case.

I couldn't see anywhere in your code where you were calculating any quantities such as temperature (rms velocity) or pressure. Since you say you're getting inconstant values for these quantities then I assume you must be calculating them somewhere. Was this code removed to make it more compact to post here?

BTW. I had to make a few small additions to your code to get it to run on my computer (maybe different versions of Python or Pygame). Just simple uninitialized variables. I had to add m=[] and z=0 to the initialization section. Not initializing "m" looks like an oversight, but "z" looks likes it's supposed to be initialized to either 0 or 1 somewhere within an if ... elif ... elif ... structure. I didn't fully trace the code to find where, but it must be getting through that block somehow without setting "z", so that also caused the program to crash on my computer. Anyway, putting "z=0" in the initialization section fixed the issue.

Thank you very much for your answer. I took into consideration the adjustments for 2D, yet the data I get is not enough accurate. I did not include the measuring code for simplicity. Since the temperature is proportional to the kinetic energy (to be precise - it is proportional to the RMS velocity squared, but the difference is not big), I measured the kinetic energy by adding the following code to the while loop:

Code:
EK = 0.5*sum([velocity[0]**2 for velocity in v[:number_of_balls]]) + 0.5*sum([velocity[1]**2 for velocity in v[:number_of_balls]])

(I summed the velocities only up to up to number_of_balls since the four last velocities are the "velocities of the walls "- the purpose of adding that is energy-conservation and momentum-conservation tests I made to check whether the collision function indeed represents elastic collisions. the momentum is fully conserved, but for some reason the kinetic energy is not fully conserved and oscillates a little - maybe this is the problem?)

the area A is boxWidth*boxHeight.

the pressure was measured as follows: with every impact of an atom with the right wall, the atom transfers to the wall momentum of 2mVx. since m=1 the total momentum transferred is dp=2V[j][0]. after every 300 iterations, I divided it by the length of the wall and by 300 (the "time", since F=dp/dt). In the code I added a "pressure" list (initially empty list) and an integer k that counts the number of iterations. I added these lines to the part in the code dealing with collisions with the right wall:

Code:
 dp+=2*v[j][0]
if k%300 == 0:
 p = dp/300*boxHeight
 print p
 dp = 0

for measuring the mean free path I created an empty list called "MFP" and added this line to the collision-function:

Code:
if (i  == number_of_balls-1 or j  == number_of_balls-1) and (i not in MFP and j not in MFP):
        MFP.append(position[i])
(I checked the mean free path of the atom with index number_of_balls-1).
from this list of coordinates of collisions one can easily find the average MFP:

Code:
MFP = np.array(MFP)
     d = []
     for i in range(1,len(MFP)):
      d.append(MFP[i]-MFP[i-1]) #d=[x,y] when x = horizontal distance between 2 collision, y =vertical distance between 2 collision
     distance = []
     for diffrence in d:
      distance.append(math.sqrt((diffrence[0])**2 + (diffrence[1])**2))
     print "MFP=",np.average(distance)
     MFP=MFP.tolist()

I am sorry for the missing z. This z is a part of the section in the code that allows you to scroll down the upper wall of the box with the mouse and reducing the area of the box, during the running of the simulation.

For better results one can take the average of the values of P,T printed during the running of the program but yet the change is not very significant. By the way, if you run the simulation for some time, letting the atoms to spread the kinetic energy between them by collisions, the velocity distribution is pretty much like Maxwell–Boltzmann distribution (as opposed to the initial velocity distribution).

this is the full code:

Code:
from __future__ import division
import pygame, sys,pygame.mixer
import math
import pylab
import numpy as np
import time
import random
from pygame.locals import*
pygame.init()

"""basic variables"""
clock = pygame.time.Clock()
font1 = pygame.font.Font(None, 17)
edgeX,edgeY = 0,0
boxWidth,boxHeight = 1000,700
size = width,height = 1000,700
centerX,centerY=int(width/2),int(height/2)
screen = pygame.display.set_mode(size)
x,y = width/2, height/2
radius = 3
number_of_atoms =230
position = []
v = []
color = []
m = []
z = 0
dp = 0
k = 0
MFP = []
"""set initial positions and velocities"""

for j in range(number_of_atoms):
    position.append([edgeX+random.randint(0,boxWidth),edgeY+random.randint(0,boxHeight),0])
    v.append([random.uniform(-5,5),random.uniform(-5,5)])
    m.append(1)
    color.append((0,0,255))
color[number_of_atoms-1]=((250,0,0))
for i in range(4):
 v.append([0,0])

def colission(a,v,b): # a - list of all atoms, v - list of all velocites (atom j is in position position[j] and travel with velocity v[j]), b - the atom we check for collisions
 for ball in a:
  if ball is not b:
   distanceX,distanceY = (b[0]-ball[0]),(b[1]-ball[1])
   distance = distanceX*distanceX + distanceY*distanceY
   if distance < 36: #radius=3,(2radius)**2=36
    ma,mb=1,1 #the mass of all atoms is 1
    i,j = a.index(ball),a.index(b)
    if (i  == number_of_balls-1 or j  == number_of_balls-1) and (i not in MFP and j not in MFP):
        MFP.append(position[i])
    change = [-0.15*distanceX,-0.15*distanceY]

    Vax,Vay = v[i][0],v[i][1]
    Vbx,Vby = v[j][0],v[j][1]

    Angle =math.atan2(distanceY,distanceX) # math.acos((distanceX/distance))
    cos,sin = math.cos(Angle),math.sin(Angle)

    #changing coordiantes:
    vg,vh=[Vag,Vah],[Vbg,Vbh]=[Vax*cos+Vay*sin,Vay*cos-Vax*sin],[Vbx*cos+Vby*sin,Vby*cos-Vbx*sin]

    #after collision:
    Va2,Vb2=(2*mb*Vbg)/(ma+mb), (2*ma*Vag)/(ma+mb) #because ma=mb the term (ma-mb)*Vag or (mb-ma)*Vbg  cancels out

    v1,v2 = [Va2,Vah] , [Vb2,Vbh]
    #changing coordiantes again:
    sin = -sin
    v1,v2 =  [(Va2*cos+Vah*sin),Vah*cos-Va2*sin], [v2[0]*cos+v2[1]*sin,v2[1]*cos-v2[0]*sin]
    v[j],v[i]= v2,v1 #update velocites
    a[i][0],a[i][1]=a[i][0] + change[0], a[i][1] + change[1] #treating overlaps
    return()

"""the loop"""

while 1:
    k+=1
    screen.fill((0,0,0))

    mouseX,mouseY=pygame.mouse.get_pos()
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        pygame.quit()
        sys.exit()
     elif event.type == MOUSEBUTTONDOWN:
        if mouseY<edgeY+50 and mouseY>edgeY-50 and mouseX<edgeX+boxWidth and mouseX>edgeX-50:
         z=1
     elif event.type == MOUSEBUTTONUP:
        z=0
    if z==1:
        dy = mouseY-edgeY
        boxHeight = boxHeight-dy
        edgeY=mouseY

    pygame.draw.rect(screen, (200,100,0), (edgeX,edgeY,boxWidth,boxHeight),1)
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        sys.exit()

    #checking for the temperature. Can be any other integer rather than 300
    if k%300 == 0:
      EK = 0.5*sum([velocity[0]**2 for velocity in v[:number_of_balls]]) + 0.5*sum([velocity[1]**2 for velocity in v[:number_of_balls]])
      print "T=",EK

    # checking the pressure:
      p = dp/(300*boxHeight)
      print "P=",p
      dp = 0

    for j in range(len(position[:number_of_atoms])):
        colission(position,v,position[j]) #check for collisions
        position[j][0]+=v[j][0]
        position[j][1]+=v[j][1]

        """checking for collisions with the walls"""

        if position[j][0]+radius>edgeX+boxWidth:
        # calculating pressure
         dp+=2*v[j][0]

         v[j][0]=-1*(v[j][0])
         position[j]=[(-radius+edgeX+boxWidth)-2,position[j][1],0]

        if position[j][0] - radius<edgeX:

         v[j][0]=-1*(v[j][0])
         position[j]=[radius+edgeX+2,position[j][1],0]

        if position[j][1]+radius>edgeY+boxHeight:

         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],(-radius+edgeY+boxHeight)-2,0]

        if position[j][1]-radius<edgeY:

         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],edgeY+2+radius,0]
    #checking foe mean free path
    if k%1000 == 0:
     MFP = np.array(MFP)
     d = []
     for i in range(1,len(MFP)):
      d.append(MFP[i]-MFP[i-1]) #d=[x,y] when x = horizontal distance between 2 collision, y =vertical distance between 2 collision
     distance = []
     for diffrence in d:
      distance.append(math.sqrt((diffrence[0])**2 + (diffrence[1])**2))
     print "MFP=",np.average(distance)
     MFP=MFP.tolist()

    clock.tick(40)
    for i in range(len(position[:number_of_atoms])):
     circle = pygame.draw.circle(screen,color[i], (int(position[i][0]),int(position[i][1])),radius)
    pygame.display.flip()
gsal said:
Here is a gas simulation using visual python.

gas-program

I know this program (for some reason it make my IDE crush) but I want to know what the problem with my program (-:

please forgive me for my english, I am not a native speaker.
 
Last edited:
This is the most updated version. now the kinetic energy (temperature) is calculated with Vrms. The ratio PA/NT is almost constant and stands on about 1.03 (when you scroll down the upper wall , reducing the area to about half of the original area, the pressure is doubled (-:)

Code:
from __future__ import division
import pygame, sys,pygame.mixer
import math
import pylab
import numpy as np
import time
import random
from pygame.locals import*
pygame.init()

"""basic variables"""
clock = pygame.time.Clock()
edgeX,edgeY = 0,0
boxWidth,boxHeight = 1000,700
size = width,height = 1000,700
centerX,centerY=int(width/2),int(height/2)
screen = pygame.display.set_mode(size)
x,y = width/2, height/2
radius = 3
number_of_atoms =230
position = []
v = []
# this is velocity distribution close to Maxwell–Boltzmann distribution
# v = [[-2.1287244853552325, 1.129085317619489], [-1.4575898925432307, -1.2711725536523415], [-2.2097302277479645, 2.7202710712771894], [0.5886788765323574, -3.795609370434213], [6.1789538542622955, -4.033423565067819], [-2.0440228542602634, 1.091295730259362], [1.6132212358775329, -0.5907913294550777], [-0.2516175054065206, -0.7569982911659228], [-0.767834098944953, -1.2465024578108552], [2.9211589754032574, 1.3399207404716227], [1.827119555517413, 0.4861092239445045], [1.4719966556288928, -1.8110668022930578], [0.014573174901874097, -1.6394058668971683], [-0.4434283584239646, 0.623965993550651], [3.0252604143752726, 2.208635209669537], [2.3417487342314587, 3.808728601455674], [-3.471920682852678, -2.87246410407716], [0.5985499889182406, 1.353504417528499], [-2.416855783145403, 1.292420605968518], [-1.443024546146792, -0.3755611375280395], [-5.2312698750465625, 0.3508321653804425], [-3.2885591872235773, 0.2360824989220558], [4.9583454096399056, 3.635330201978962], [-0.17681495748929366, -1.9062349065461373], [5.052487371301375, -0.7498305180096287], [-1.091483827298553, -1.3134606347484017], [-4.569292937508718, 2.2657925196920705], [0.024862400530593964, 1.038245416716403], [-2.7612212253634536, -2.4362409251158947], [3.751202862544148, -1.2884358964475193], [-5.544759276849922, 1.633206866449836], [-1.4929803152561631, 7.427959261771754], [0.6910384380395272, -2.3210682127246605], [4.966179676366409, 8.14277050918934], [-2.939921609018506, 4.247572878924255], [3.46280491334585, -0.22832898919642597], [3.7568113482449323, -3.9818124252045584], [-5.81603207616, -1.8953289928657058], [1.8922119487626696, 5.647835085379633], [1.5865111481144616, 2.440716397288515], [-2.559241988449605, 6.259315242017289], [1.560095547900185, -2.43209068738827], [0.2948421732901573, 0.30410261965283103], [-1.3397082002559542, -3.6253780052346816], [-3.605609964313315, 0.3837913068513812], [0.5357050593902128, 5.3593553783442704], [-1.792412888558205, 0.862244087962059], [1.162155955027183, -2.9130269821889017], [-3.4850237012054675, -7.674228647409126], [4.656126575705954, 4.584905781321144], [-0.7571297335955761, -0.5059533871455572], [-1.2719565404060598, -5.869202492280124], [-1.0217834106552188, -0.7805395470606652], [-0.8630572822069764, 3.0094803400894166], [4.200359299186116, -0.578968615806449], [-0.7869975423781066, 4.19567092164654], [2.633443039109919, 2.2318655698837317], [3.602440137034528, 2.294935016747216], [3.4289832767298516, 0.4544258244837671], [4.513819006019582, -1.2295456367701252], [-0.07632380913320802, 1.2072539498543464], [-1.8068756201328224, 2.74995848527786], [-2.976227145535782, -6.563635270523498], [0.5026244572731093, 3.4693018984139234], [2.996202980131871, 4.699392928649715], [-3.2899406516732057, 1.3134134276847456], [1.718079815818962, -0.1683187895044323], [-0.13518393017429897, 5.54700587906911], [1.8790135713840248, 2.0266924690419112], [3.5647748704942472, -0.02369178903435687], [-2.3926060753474827, 3.657019905033295], [6.4969728497115256, -1.0367301642558044], [-0.023465299643890325, 2.3272129564146233], [-0.6673448250322047, 3.716099643539505], [-4.188916072667548, 1.8798793523488007], [1.6985531474315374, -4.256524967353668], [-3.6760110444317227, 0.450815452016781], [0.8593856519469103, 6.548276513256727], [-0.6874305714315574, 3.924788489008713], [-1.6280123105285504, 4.3272921365645685], [1.9172239398967272, 2.256850677753119], [0.15416495499730978, -2.431193698081671], [1.5053797733536585, -0.23695421632733982], [-2.9137062125131745, -1.8971562459288949], [2.8541364655469073, -0.456823611080871], [-0.09661346709533003, 2.9051650821793364], [0.5072015945158301, -2.2672681386822875], [0.2545044950869553, 4.621789703077026], [-2.243872975995369, -0.8370408949452286], [-0.8941426424681549, -7.172708681656136], [0.20169032842291273, 2.4814670906899496], [-1.8964009017655787, -3.8470469473042566], [0.1977415306381295, 0.9954546081169863], [1.2177433260585913, -3.516139330055328], [1.4584436116027801, -1.5102918861304389], [-4.688466851545976, -0.18279688006604267], [1.1066366006626174, 1.1094869103094414], [-5.898434347641582, -1.2255529598860404], [-1.1645661115261157, 1.0758904080219807], [0.19564921451363354, 0.942295215044142], [-0.958888900885171, 1.858851545058297], [0.86195445606525, 0.0560058442935831], [-1.8794681665160713, -0.5882204653385881], [-2.441063036455345, 0.732607361354868], [2.7193057366101, 1.9389437680157378], [-1.5313904527595503, -1.5367326619406922], [-4.128124335095066, 1.0843340884023764], [-1.7533476670721027, -2.208124824940983], [-1.6950872812235964, -2.277644406649925], [4.063102097910239, -0.6585604177104856], [1.3842578839330968, -2.9221362400820685], [0.47579102203538015, -0.8945850746569246], [0.8453488171596295, 2.052097091864293], [-2.6443681964978722, -0.2057732479640893], [1.5566398411524949, -0.9330184493337836], [-2.9263004794535545, 5.026437883117941], [0.80645416145117, 3.758828723524164], [3.284929090923728, -3.6227000661580258], [-3.447836059212689, -3.647310284015568], [-1.625662257384021, 3.072709815013726], [0.7602769424162704, 4.794024860706607], [-2.2847585561416968, -0.517625690763838], [0.6856737997305061, 3.1792462708961686], [7.434487717013161, 1.9439019283071575], [-2.388321304737894, -1.899416395264461], [0.6252479500513946, 3.369328418717423], [-1.004824462893196, 5.761855273203045], [3.411500943108601, -2.1786472181528787], [0.895632244853948, -1.9381317634703237], [0.8557814888026711, -3.3262602285629748], [-0.23577428717797821, -3.4613930312339027], [2.2984500432385984, 0.2401807812854364], [0.9929487664755621, -0.7603012580415649], [3.9735309321486705, 4.517661732296059], [-0.06734888812098228, -2.750813451991558], [3.1752095910261064, 0.9315615053102624], [-0.026244444512734, -2.728425205461482], [-2.3089666688277997, 8.512834150279348], [-0.9798046514458889, 3.318884096997367], [1.2691900121950108, 2.3290013721534812], [-0.3295679748583097, -1.3852726642934186], [5.065812645471419, -3.181915702213119], [0.9967362401567141, -3.4265072249079513], [-4.6615177233539065, 4.191631712184568], [-3.6756680914878666, 4.365885101440132], [-1.6044671511492943, 2.4026543610193816], [-3.4870059930214214, 1.4797639765420691], [-1.4061910304529295, 2.5507576873009636], [-0.49588655199546927, -0.7718544057641696], [0.31812248876170823, 3.8808675439605653], [0.8297651194240518, 1.1034164139441218], [0.955685077915639, -1.5157001184057073], [1.8606548559009104, -2.9794615857147617], [-7.024947741623986, 1.522061884819359], [2.731956552179851, -3.06780587632241], [0.41716496504854017, -1.691338524499796], [-4.576483535748092, -0.3337037330114587], [-8.676712082318103, -0.19111682462656088], [-0.843767089393642, -1.3400023244380612], [0.9218786743708282, 1.0126582359750793], [-1.0143251878634154, 1.188754004214144], [0.2806049374277204, -4.430459397598726], [-3.3704337274762484, -1.691201925438966], [0.40900347579195095, -0.5204500005128022], [0.2190568893603247, -0.20904850973844363], [-1.1245110690995426, 1.096377357434669], [-0.2972479882775855, 1.4440529160443347], [3.6352137258859685, 0.6692525456857008], [-0.83448505499437, -3.478006844512695], [-5.975529230813983, -5.446779021576986], [1.9480598050090485, -1.459692330763727], [-1.5793475649127857, 1.8953604331776843], [-1.051268733938766, -1.5563922957477605], [2.7055153671479326, 3.5996417861276298], [-1.6945531224440167, -2.2492968341614965], [-6.396378137877722, 4.7435536584544336], [6.115917787317734, 2.211656076002754], [-4.098109410858985, 4.734428742541122], [8.025240069344465, 5.19664002926344], [1.5711890449539099, 7.225795964291294], [1.4568608542881973, 0.5214991953781499], [0.10644490460908843, 0.2787937294079582], [4.555357276896172, 0.8261472271107984], [-4.03032262225062, -0.23569698523079152], [-0.1440683864790067, -0.0371783175326322], [-0.08869216199854768, 1.9774893189749678], [-0.4939406287573891, -5.062897437084835], [3.286740574147082, -0.2442005475869966], [3.1460674470508687, -4.08913639326025], [-4.195191850920548, 3.619360827313388], [-0.06533450721116435, -0.872911940151411], [-1.1120274875897798, 1.6992612421171176], [1.1595191152242585, 0.8163290947290789], [2.562523036898191, -2.428415569295686], [1.0525434696343794, -1.6587306494640617], [3.949853363491484, -3.448051574307901], [-4.898777869231424, -0.5068961237823801], [3.804126963250541, -3.277498044839827], [1.6778773851147775, -2.6711386526611856], [-2.900680891033825, -1.0387419128075335], [-4.848605045148634, 1.8898063518521453], [-2.502675276990972, -2.0535025006104544], [0.5499822935629051, 2.9646298126471278], [-7.338907640997098, 0.0409109530153291], [1.1332902114965717, -0.5468540934107438], [0.16782928688640625, 0.7904767586653285], [1.2582474073794312, 3.0036748546765084], [-0.060684638140671154, -5.053844672495908], [0.9567293470016475, 1.1601246604631166], [-2.8149165015429323, -1.715933191498082], [3.503878199350167, -1.2699697672984964], [2.6067848162696183, -6.063286021185606], [3.7337356915825195, 2.9595867065597177], [-1.3250323138536988, 4.262724531276803], [0.6644042107692495, -0.8352146276981922], [-1.118101489819965, -1.7698967696742673], [2.6978724771433944, 2.6726209521864996], [3.479962638287302, -0.7386315864145241], [-3.2997577760130223, -2.700179680457352], [2.158909231190396, -2.411481523612787], [1.8359060462975636, -2.5338795853408027], [-2.8168490942868356, -1.6877315173363834], [5.927835811346032, 2.4666987802697182], [-1.08505989013212, 2.4804614069323674], [0.7831132294798451, -0.47206045038222133], [0.5537611071882644, -1.9306913340835448], [2.705853755959905, 1.7762306202558578], [-1.2475770658729126, -0.24937838151687836], [1.609192961725411, -6.182121058659931], [0.7438527245790993, 0.4988183863315878], [0, 0], [0, 0], [0, 0], [0, 0]]
color = []
m = []
z = 0
dp = 0
k = 0
MFP = []
"""set initial positions and velocities"""

for j in range(number_of_atoms):
    position.append([edgeX+random.randint(0,boxWidth),edgeY+random.randint(0,boxHeight),0])
    v.append([random.uniform(-5,5),random.uniform(-5,5)])
    m.append(1)
    color.append((0,0,255))
color[number_of_atoms-1]=((250,0,0))
for i in range(4):
 v.append([0,0])

def colission(a,v,b): # a - list of all atoms, v - list of all velocites (atom j is in position position[j] and travel with velocity v[j]), b - the atom we check for collisions
 for ball in a:
  if ball is not b:
   distanceX,distanceY = (b[0]-ball[0]),(b[1]-ball[1])
   distance = distanceX*distanceX + distanceY*distanceY
   if distance < 36: #radius=3,(2radius)**2=36
    ma,mb=1,1 #the mass of all atoms is 1
    i,j = a.index(ball),a.index(b)
    if (i  == number_of_atoms-1 or j  == number_of_atoms-1) and (i not in MFP and j not in MFP):
        MFP.append(position[i])
    change = [-0.15*distanceX,-0.15*distanceY]

    Vax,Vay = v[i][0],v[i][1]
    Vbx,Vby = v[j][0],v[j][1]

    Angle =math.atan2(distanceY,distanceX) # math.acos((distanceX/distance))
    cos,sin = math.cos(Angle),math.sin(Angle)

    #changing coordiantes:
    vg,vh=[Vag,Vah],[Vbg,Vbh]=[Vax*cos+Vay*sin,Vay*cos-Vax*sin],[Vbx*cos+Vby*sin,Vby*cos-Vbx*sin]

    #after collision:
    Va2,Vb2=(2*mb*Vbg)/(ma+mb), (2*ma*Vag)/(ma+mb) #because ma=mb the term (ma-mb)*Vag or (mb-ma)*Vbg  cancels out

    v1,v2 = [Va2,Vah] , [Vb2,Vbh]
    #changing coordiantes again:
    sin = -sin
    v1,v2 =  [(Va2*cos+Vah*sin),Vah*cos-Va2*sin], [v2[0]*cos+v2[1]*sin,v2[1]*cos-v2[0]*sin]
    v[j],v[i]= v2,v1 #update velocites
    a[i][0],a[i][1]=a[i][0] + change[0], a[i][1] + change[1] #treating overlaps
    return()

"""the loop"""

while 1:
    k+=1
    screen.fill((0,0,0))

    mouseX,mouseY=pygame.mouse.get_pos()
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        pygame.quit()
        sys.exit()
     elif event.type == MOUSEBUTTONDOWN:
        if mouseY<edgeY+50 and mouseY>edgeY-50 and mouseX<edgeX+boxWidth and mouseX>edgeX-50:
         z=1
     elif event.type == MOUSEBUTTONUP:
        z=0
    if z==1:
        dy = mouseY-edgeY
        boxHeight = boxHeight-dy
        edgeY=mouseY

    pygame.draw.rect(screen, (200,100,0), (edgeX,edgeY,boxWidth,boxHeight),1)
    for event in pygame.event.get():
     if event.type == pygame.QUIT:
        sys.exit()

    #checking for the temperature. Can be any other integer rather than 300
    if k%300 == 0:
      v_rms = math.sqrt(sum(velocity[0]**2 + velocity[1]**2 for velocity in v[:number_of_atoms])/number_of_atoms) #Vrms = sqrt(sum(Vx**2+Vy**2)/num of atoms)
      EK = 0.5*1*(v_rms)**2
      print "T=",EK

    # checking the pressure:
      p = dp/(300*boxHeight)
      print "P=",p
      dp = 0

    for j in range(len(position[:number_of_atoms])):
        colission(position,v,position[j]) #check for collisions
        position[j][0]+=v[j][0]
        position[j][1]+=v[j][1]

        """checking for collisions with the walls"""

        if position[j][0]+radius>edgeX+boxWidth:
        # calculating pressure
         dp+=2*v[j][0]

         v[j][0]=-1*(v[j][0])
         position[j]=[(-radius+edgeX+boxWidth)-2,position[j][1],0]

        if position[j][0] - radius<edgeX:

         v[j][0]=-1*(v[j][0])
         position[j]=[radius+edgeX+2,position[j][1],0]

        if position[j][1]+radius>edgeY+boxHeight:

         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],(-radius+edgeY+boxHeight)-2,0]

        if position[j][1]-radius<edgeY:

         v[j][1]=-1*(v[j][1])
         position[j]=[position[j][0],edgeY+2+radius,0]
    #checking foe mean free path
    if k%1000 == 0:
     MFP = np.array(MFP[len(MFP)-100:len(MFP)-1])
     d = []
     for i in range(1,len(MFP)):
      d.append(MFP[i]-MFP[i-1]) #d=[x,y] when x = horizontal distance between 2 collision, y =vertical distance between 2 collision
     distance = []
     for difference in d:
      distance.append(math.sqrt((difference[0])**2 + (difference[1])**2))
     print "MFP=",np.average(distance)
     MFP=MFP.tolist()

    clock.tick(40)
    for i in range(len(position[:number_of_atoms])):
     circle = pygame.draw.circle(screen,color[i], (int(position[i][0]),int(position[i][1])),radius)
    pygame.display.flip()
 
Last edited:
  • Like
Likes Catarina
Thread 'Star maps using Blender'
Blender just recently dropped a new version, 4.5(with 5.0 on the horizon), and within it was a new feature for which I immediately thought of a use for. The new feature was a .csv importer for Geometry nodes. Geometry nodes are a method of modelling that uses a node tree to create 3D models which offers more flexibility than straight modeling does. The .csv importer node allows you to bring in a .csv file and use the data in it to control aspects of your model. So for example, if you...
I tried a web search "the loss of programming ", and found an article saying that all aspects of writing, developing, and testing software programs will one day all be handled through artificial intelligence. One must wonder then, who is responsible. WHO is responsible for any problems, bugs, deficiencies, or whatever malfunctions which the programs make their users endure? Things may work wrong however the "wrong" happens. AI needs to fix the problems for the users. Any way to...
Back
Top