Skip to content

Commit 833bb2d

Browse files
authored
Merge pull request #58 from shishlo/main
The SliceBySlice2D Poisson solver for Synchrotron ring fixed and tested at J-PARC
2 parents 709a5cc + 03fdf93 commit 833bb2d

16 files changed

+2260
-559
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#-------------------------------------------------------------
2+
# This is a test that MPI is initialized and Bunch class
3+
# instance can feel this MPI
4+
#-------------------------------------------------------------
5+
"""
6+
>mpirun -np 2 python mpi_initialization_test.py
7+
"""
8+
9+
import sys
10+
import math
11+
import random
12+
13+
from orbit.core.orbit_mpi import mpi_comm, MPI_Comm_rank, MPI_Comm_size, MPI_Bcast
14+
from orbit.core.orbit_mpi import mpi_datatype, mpi_op
15+
from orbit.core.orbit_mpi import MPI_Bcast
16+
from orbit.core import orbit_mpi
17+
18+
from orbit.core.bunch import Bunch
19+
20+
21+
mpi_init = orbit_mpi.MPI_Initialized()
22+
print ("debug mpi is initialized =",mpi_init," should be not zero.")
23+
24+
rank = orbit_mpi.MPI_Comm_rank(mpi_comm.MPI_COMM_WORLD)
25+
size = orbit_mpi.MPI_Comm_size(mpi_comm.MPI_COMM_WORLD)
26+
27+
if(rank == 0):
28+
print ("debug there should only one line like this rank=",rank," N CPUs = ",size)
29+
30+
n_particles = 10
31+
32+
bunch = Bunch()
33+
for ind in range(n_particles):
34+
bunch.addParticle(0.,0.,0.,0.,0.,0.)
35+
36+
n_particles_global = bunch.getSizeGlobal()
37+
if(rank == 0):
38+
print ("debug should be only one: rank=",rank," n_particles_global =",n_particles_global," it should be =",n_particles*size)
39+
40+
if(rank == 0):
41+
print ("debug should be only one Stop.")
42+
43+
sys.exit(mpi_init)
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
#---------------------------------------------------------
2+
# This example tracks the particles uniformly distributed
3+
# inside the sphere in the bunch rest coordinate system.
4+
# After tracking through the drift one or several times
5+
# the ratios of x,y,z rms sizes should be the same.
6+
# Here we use 2.5D Rick Baartman's Space Charge model.
7+
#---------------------------------------------------------
8+
# 2.5D Rick Baartman's Space Charge model should not work
9+
# for the linac case here it is just as example of setting
10+
# another SC model.
11+
# N.B. Model is wrong!
12+
#---------------------------------------------------------
13+
14+
import sys
15+
import math
16+
import random
17+
18+
from orbit.core.bunch import Bunch, BunchTwissAnalysis
19+
20+
from orbit.lattice import AccLattice, AccNode, AccActionsContainer
21+
from orbit.teapot import teapot
22+
23+
from orbit.core.spacecharge import SpaceChargeCalc3D
24+
from orbit.space_charge.sc3d import setSC3DAccNodes
25+
26+
from orbit.space_charge.sc3d import setUniformEllipsesSCAccNodes
27+
from orbit.core.spacecharge import SpaceChargeCalcUnifEllipse
28+
29+
from orbit.space_charge.sc2p5d import setSC2p5DrbAccNodes
30+
from orbit.core.spacecharge import SpaceChargeCalc2p5Drb
31+
32+
#------------------------------
33+
# Let's make everything random
34+
#------------------------------
35+
random.seed(10)
36+
37+
#------------------------------
38+
# Auxilary functions
39+
#------------------------------
40+
41+
def func_theory(x):
42+
"""
43+
The function used in the charged sphere expansion dynamics calculation.
44+
See the presentation.
45+
"""
46+
val = math.sqrt(abs(x**2-1))
47+
val = math.log(x+val)/2 + x*val/2
48+
return val
49+
50+
def getR_Theory(s_path,r_init,R,Ntot,bunch):
51+
"""
52+
The root finding in the charged sphere expansion dynamics calculation.
53+
See the presentation.
54+
s_path - path length / drift length []
55+
r_init - initial distance from the sphere center [m]
56+
R - bunch sphere radius [m]
57+
Ntot - total macro-size of the bunch
58+
beta - relativistic beta
59+
r_classic - classical radius of particle
60+
"""
61+
r_classic = bunch.classicalRadius()
62+
gamma = bunch.getSyncParticle().gamma()
63+
beta = bunch.getSyncParticle().beta()
64+
val = math.sqrt((r_classic*Ntot/R**3)/2)*s_path/(gamma*beta)
65+
#---- Now we solve equation val = func_theory(x) for x
66+
x_min = 1.000000001
67+
x_max = 10.
68+
x = (x_min + x_max)/2.
69+
#print ("debug s_path=",s_path," val=",val)
70+
n_iter = 15
71+
count = 0
72+
f_min = func_theory(x_min)
73+
f_max = func_theory(x_max)
74+
f_val = func_theory((x_min + x_max)/2.)
75+
while(count < n_iter):
76+
x = (x_min + x_max)/2.
77+
f_val = func_theory(x)
78+
if(val <= f_val):
79+
f_max = f_val
80+
x_max = x
81+
count += 1
82+
continue
83+
if(val >= f_val):
84+
f_min = f_val
85+
x_min = x
86+
count += 1
87+
continue
88+
r_res = 1000.*r_init*x**2
89+
#print ("debug s_path=",s_path," val=",val," f_val=",f_val," x=",x," r_res=",r_res)
90+
return r_res
91+
92+
#----------------------------------------
93+
# Uniform sphere distribution functions
94+
#----------------------------------------
95+
96+
def getUniformXYZ(radius,gamma):
97+
"""
98+
Uniform distribution inside the sphere.
99+
Z-direction is contracted by relativistic gamma
100+
"""
101+
(x,y,z) = (radius,radius,radius)
102+
r = math.sqrt(x**2 + y**2 + z**2)
103+
while(r > radius):
104+
x = radius*(1.0 - 2*random.random())
105+
y = radius*(1.0 - 2*random.random())
106+
z = radius*(1.0 - 2*random.random())
107+
r = math.sqrt(x**2 + y**2 + z**2)
108+
return (x,y,z/gamma)
109+
110+
print ("Start.")
111+
#---------------------------------
112+
#make an initial bunch
113+
#---------------------------------
114+
b_init = Bunch()
115+
bunch_radius = 0.005 # m
116+
bunch_length = 10.0 # m
117+
nParts = 1000000
118+
total_macroSize = 1.0e+11
119+
energy = 0.4 # GeV
120+
121+
syncPart = b_init.getSyncParticle()
122+
syncPart.kinEnergy(energy)
123+
beta = syncPart.beta()
124+
gamma = syncPart.gamma()
125+
print ("==================================================")
126+
print ("Mass[MeV] = %8.3f "%(b_init.mass()*1000.))
127+
print ("Kinetic energy[MeV] = %8.3f "%(energy*1000.))
128+
print ("gamma = %8.5f "%gamma)
129+
print ("Total macrosize = %12.5e "%total_macroSize)
130+
print ("==================================================")
131+
132+
#------------------------------------------------
133+
#---- generate an uniform sphere distribution
134+
#---- without energy or momentum spread
135+
#------------------------------------------------
136+
for ip in range(nParts):
137+
(x,y,z) = getUniformXYZ(bunch_radius,gamma)
138+
b_init.addParticle(x,0.,y,0.,z,0.)
139+
140+
#-------------------------------
141+
# set bunch parameters
142+
#-------------------------------
143+
nParticlesGlobal = b_init.getSizeGlobal()
144+
b_init.macroSize(total_macroSize/nParticlesGlobal)
145+
print ("Total numbers of macro-particles = ",nParticlesGlobal)
146+
147+
#----------------------------------------------
148+
#---- Analysis of the initial bunch
149+
#----------------------------------------------
150+
twiss_analysis = BunchTwissAnalysis()
151+
twiss_analysis.analyzeBunch(b_init)
152+
153+
x_rms = math.sqrt(twiss_analysis.getCorrelation(0,0)) * 1000.0
154+
y_rms = math.sqrt(twiss_analysis.getCorrelation(2,2)) * 1000.0
155+
z_rms = math.sqrt(twiss_analysis.getCorrelation(4,4)) * 1000.0
156+
157+
print ("==========Before Traking=====================")
158+
print ("Initial x_rms[mm] = %6.5f x_rms/y_rms = %6.5f "%(x_rms,x_rms/y_rms))
159+
print ("Initial y_rms[mm] = %6.5f x_rms/(z_rms*gamma) = %6.5f "%(y_rms,x_rms/(z_rms*gamma)))
160+
print ("Initial z_rms[mm] = %6.5f x_rms/(z_rms*gamma) = %6.5f "%(z_rms,x_rms/(z_rms*gamma)))
161+
print ("=============================================")
162+
#------------------------------------------
163+
# Initial Bunch is ready
164+
# Now let's make a lattice
165+
#------------------------------------------
166+
167+
def getLattice(lattice_length,n_parts,calc3d,pipe_radius):
168+
elem = teapot.DriftTEAPOT("my_drift")
169+
elem.setLength(lattice_length)
170+
elem.setnParts(n_parts)
171+
teapot_lattice = teapot.TEAPOT_Lattice("teapot_lattice")
172+
teapot_lattice.addNode(elem)
173+
teapot_lattice.initialize()
174+
# we will put SC nodes as frequently as possible.
175+
# In this case one for each part of the Drift node
176+
sc_path_length_min = 0.1
177+
scNodes_arr = setSC2p5DrbAccNodes(teapot_lattice, sc_path_length_min, calc3d,pipe_radius)
178+
#print ("debug n sc nodes=",len(scNodes_arr))
179+
return teapot_lattice
180+
181+
#-------------------------------------------------------------
182+
# set 2.5D Rick Baartman's Space Charge model.
183+
# This model should not work for linac case
184+
# here it is just as example of setting another SC model
185+
#-------------------------------------------------------------
186+
sizeX = 64
187+
sizeY = 64
188+
sizeZ = 64
189+
pipe_radius = 0.100
190+
calc3d = SpaceChargeCalc2p5Drb(sizeX,sizeY,sizeZ)
191+
192+
lattice_length = 0.5 # the length of the drift
193+
n_parts = 30 # number of parts on what the drift will be chopped, or the number of SC nodes
194+
lattice = getLattice(lattice_length,n_parts,calc3d,pipe_radius)
195+
196+
print ("Lattice length[m] = %6.3f "%lattice_length)
197+
print ("Number of parts in the lattice = ",n_parts)
198+
199+
#--------------------------------------------------------------------
200+
# Create a new bunch, copy everything from b_init to this new bunch
201+
#--------------------------------------------------------------------
202+
bunch = Bunch()
203+
b_init.copyBunchTo(bunch)
204+
205+
#-------------------------------------------------------------------
206+
#---- Here we add three particles - along x,y,z axises at
207+
#---- r_bunch/2 disstance from the center. We will use them to
208+
#---- compare analytical solution with the PyORBIT tracking,
209+
#---- N.B. : adding 3 particles did not change total charge much.
210+
#-------------------------------------------------------------------
211+
ip_arr = [nParticlesGlobal,nParticlesGlobal+1,nParticlesGlobal+2]
212+
r_in = 0.5*bunch_radius
213+
bunch.addParticle(-r_in,0.,0.,0.,0.,0.)
214+
bunch.addParticle(0.,0.,r_in,0.,0.,0.)
215+
bunch.addParticle(0.,0.,0.,0.,r_in/gamma,0.)
216+
r_in *= 1000 # now in [mm]
217+
218+
#-------------------------------------------------------
219+
#---- Let's track bunch through the drift several times
220+
#-------------------------------------------------------
221+
s_path = 0.
222+
223+
print ("s[m] r_rms[mm] r1[mm] r2[mm] r3[mm] r_theory[mm] ")
224+
225+
for ind in range(20):
226+
#---------------------------------------
227+
#track the bunch through the lattice
228+
#---------------------------------------
229+
lattice.trackBunch(bunch)
230+
231+
s_path += lattice_length
232+
233+
#----------------------------------------------
234+
#---- Analysis of the final bunch
235+
#----------------------------------------------
236+
twiss_analysis.analyzeBunch(bunch)
237+
238+
x_rms = math.sqrt(twiss_analysis.getCorrelation(0,0)) * 1000.0
239+
y_rms = math.sqrt(twiss_analysis.getCorrelation(2,2)) * 1000.0
240+
z_rms = math.sqrt(twiss_analysis.getCorrelation(4,4)) * 1000.0
241+
r_rms = math.sqrt(x_rms**2 + y_rms**2 + (z_rms*gamma)**2)
242+
243+
st = ""
244+
r_out = 0.
245+
for ip in ip_arr:
246+
z = bunch.z(ip)*gamma
247+
x = bunch.x(ip)
248+
y = bunch.y(ip)
249+
xp = bunch.xp(ip)*1000
250+
r_out = 1000.*math.sqrt(x**2 + y**2 + z**2)
251+
st += " %6.3f "%(r_out)
252+
253+
254+
r_out_th = getR_Theory(s_path,0.5*bunch_radius,bunch_radius,total_macroSize,bunch)
255+
256+
#r_classic = bunch.classicalRadius()
257+
#gamma = bunch.getSyncParticle().gamma()
258+
#beta = bunch.getSyncParticle().beta()
259+
260+
#xp_th = r_classic*total_macroSize*s_path*r_in/(bunch_radius**3)/(gamma*beta)**2
261+
262+
print (" %4.3f %6.3f "%(s_path,r_rms),st," %6.3f "%r_out_th)
263+
264+
print ("==========After Traking=======================")
265+
print ("x_rms[mm] = %6.5f x_rms/y_rms = %6.5f "%(x_rms,x_rms/y_rms))
266+
print ("y_rms[mm] = %6.5f y_rms/(z_rms*gamma) = %6.5f "%(y_rms,y_rms/(z_rms*gamma)))
267+
print ("z_rms[mm] = %6.5f x_rms/(z_rms*gamma) = %6.5f "%(z_rms,x_rms/(z_rms*gamma)))
268+
print ("=============================================")
269+
270+
print("Finish.")
271+
sys.exit(0)

0 commit comments

Comments
 (0)