Skip to content

Commit 7dfc171

Browse files
authored
Merge pull request #33 from shishlo/main
2 parents ac20928 + bb94cb6 commit 7dfc171

File tree

7 files changed

+199
-2
lines changed

7 files changed

+199
-2
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#! /usr/bin/env python
2+
3+
"""
4+
This script is the linac solenoid test.
5+
We will compare results with TEAPOT solenoid and will test the lattice parser.
6+
"""
7+
8+
import sys
9+
import math
10+
import random
11+
import time
12+
13+
from orbit.py_linac.linac_parsers import SNS_LinacLatticeFactory
14+
15+
from orbit.core.bunch import Bunch
16+
17+
from orbit.lattice import AccLattice, AccNode, AccActionsContainer
18+
19+
from orbit.py_linac.lattice import Quad,Solenoid
20+
21+
from orbit.teapot import SolenoidTEAPOT
22+
23+
#------------------------------------------------
24+
# Start of Script
25+
#------------------------------------------------
26+
27+
def printBunch(text,bunch):
28+
"""
29+
Print particles coordinates in the bunch.
30+
"""
31+
print (text)
32+
b = bunch
33+
for ind in range(bunch.getSize()):
34+
(x, xp, y, yp, z, dE) = (b.x(ind),b.xp(ind),b.y(ind),b.yp(ind),b.z(ind),b.dE(ind))
35+
st = " %2d "%ind
36+
st += " %12.5g , %12.5g "%(x*1000., xp*1000.)
37+
st += " %12.5g , %12.5g "%(y*1000., yp*1000.)
38+
st += " %12.5g , %12.5g "%(z, dE*1000.)
39+
print (st)
40+
print ("==================================")
41+
42+
names = ["TEST_Seq",]
43+
44+
sns_linac_factory = SNS_LinacLatticeFactory()
45+
sns_linac_factory.setMaxDriftLength(0.5)
46+
47+
# ---- the XML file name with the structure
48+
xml_file_name = "test_solenoid_lattice.xml"
49+
50+
# ---- make lattice from XML file
51+
accLattice = sns_linac_factory.getLinacAccLattice(names, xml_file_name)
52+
53+
print ("============ Test Lattice =============")
54+
for ind,node in enumerate(accLattice.getNodes()):
55+
st = "ind= %2d "%ind
56+
st += " node= %35s "%node.getName()
57+
st += " length[m] = %6.4f "%node.getLength()
58+
st += " nParts= %2d "%node.getnParts()
59+
st += " type= %10s "%node.getType()
60+
print (st)
61+
print ("========================================")
62+
63+
64+
node_soln = accLattice.getNodesOfClass(Solenoid)[0]
65+
node_soln_ind = accLattice.getNodeIndex(node_soln)
66+
print ("Solenoid field B=",node_soln.getParam("B"))
67+
68+
#---- Results should be the same for any parts in the solenoid node
69+
nSolParts = 10
70+
node_soln.setnParts(nSolParts)
71+
print (" nParts= %2d "%node_soln.getnParts())
72+
73+
bunch_init = Bunch()
74+
syncPart = bunch_init.getSyncParticle()
75+
bunch_init.mass(0.9382723)
76+
bunch_init.charge(+1.0)
77+
syncPart.kinEnergy(0.003)
78+
79+
(x, xp, y, yp, z, dE) = (0.,0.,0.,0.,0.,0.)
80+
bunch_init.addParticle(x, xp, y, yp, z, dE)
81+
82+
(x, xp, y, yp, z, dE) = (0.001,0.001,-0.001,-0.001,0.1,0.00002)
83+
bunch_init.addParticle(x, xp, y, yp, z, dE)
84+
bunch_init.addParticle(x/2, xp/2, y/2, yp/2, z/2, dE/2)
85+
86+
(x, xp, y, yp, z, dE) = (-0.001,-0.001,+0.001,+0.001,-0.1,-0.00002)
87+
bunch_init.addParticle(x, xp, y, yp, z, dE)
88+
bunch_init.addParticle(x/2, xp/2, y/2, yp/2, z/2, dE/2)
89+
90+
#---- set up design
91+
accLattice.trackDesignBunch(bunch_init)
92+
93+
#---- track bunch to the solenoid start
94+
accLattice.trackBunch(bunch_init,None,None,0,node_soln_ind-1)
95+
96+
printBunch("========= Initial Bunch: before Solenoid ",bunch_init)
97+
98+
bunch = Bunch()
99+
bunch_init.copyBunchTo(bunch)
100+
101+
#---- track bunch through the solenoid
102+
accLattice.trackBunch(bunch,None,None,node_soln_ind,node_soln_ind)
103+
104+
printBunch("========= Bunch After: after Solenoid ",bunch)
105+
106+
#----------------------------------------------
107+
# Now let's create TEAPOT solenoid and track
108+
# the same bunch through it.
109+
#----------------------------------------------
110+
111+
soln_teapot = SolenoidTEAPOT("solenoid_teapot")
112+
soln_teapot.setParam("B",node_soln.getParam("B"))
113+
soln_teapot.setLength(node_soln.getLength())
114+
115+
bunch = Bunch()
116+
bunch_init.copyBunchTo(bunch)
117+
soln_teapot.trackBunch(bunch)
118+
119+
printBunch("========= Bunch After: after TEAPOT Solenoid - should be the same",bunch)
120+
121+
print ("Stop.")
122+
123+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" ?>
2+
<ess>
3+
<TEST_Seq bpmFrequency="7.0442E8" length="3" name="MEBT">
4+
<accElement length="0.0" name="TEST_START" pos="0.0" type="MARKER">
5+
<parameters/>
6+
</accElement>
7+
<accElement length="0.10" name="QV01" pos="0.5" type="QUAD">
8+
<parameters aperture="0.5" aprt_type="1" field="-10.0"/>
9+
</accElement>
10+
<accElement length="1" name="SL00" pos="1.5" type="SOLENOID">
11+
<parameters aperture="0.5" aprt_type="1" B="10.0"/>
12+
</accElement>
13+
<accElement length="0.10" name="QV01" pos="2.5" type="QUAD">
14+
<parameters aperture="0.5" aprt_type="1" field="+10.0"/>
15+
</accElement>
16+
<accElement length="0.0" name="TEST_EDN" pos="2.9999999" type="MARKER">
17+
<parameters/>
18+
</accElement>
19+
</TEST_Seq>
20+
</ess>

py/orbit/py_linac/lattice/LinacAccNodes.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,32 @@ def track(self, paramsDict):
849849
self.tracking_module.kick(bunch, kickX, kickY, 0.0)
850850
self.tracking_module.drift(bunch, length / 2.0)
851851

852+
class Solenoid(BaseLinacNode):
853+
"""
854+
Solenoid TEAPOT based element.
855+
"""
856+
857+
def __init__(self, name="solenoid no name"):
858+
"""
859+
Constructor. Creates the Solenoid TEAPOT based element.
860+
"""
861+
BaseLinacNode.__init__(self, name)
862+
self.setType("solenoid")
863+
self.addParam("B", 0.0)
864+
865+
def track(self, paramsDict):
866+
"""
867+
The Solenoid TEAPOT class implementation of the
868+
AccNodeBunchTracker class track(probe) method.
869+
"""
870+
index = self.getActivePartIndex()
871+
length = self.getLength(index)
872+
B = self.getParam("B")
873+
bunch = paramsDict["bunch"]
874+
useCharge = 1
875+
if "useCharge" in paramsDict:
876+
useCharge = paramsDict["useCharge"]
877+
TPB.soln(bunch, length, B, useCharge)
852878

853879
class AbstractRF_Gap(BaseLinacNode):
854880
"""

py/orbit/py_linac/lattice/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from orbit.py_linac.lattice.LinacAccNodes import BaseLinacNode, LinacNode, LinacMagnetNode
1212
from orbit.py_linac.lattice.LinacAccNodes import MarkerLinacNode, Drift, Quad, AbstractRF_Gap, Bend
13+
from orbit.py_linac.lattice.LinacAccNodes import Solenoid
1314
from orbit.py_linac.lattice.LinacAccNodes import DCorrectorH, DCorrectorV
1415
from orbit.py_linac.lattice.LinacAccNodes import ThickKick
1516

@@ -53,6 +54,7 @@
5354
__all__.append("DCorrectorV")
5455
__all__.append("ThickKick")
5556
__all__.append("Bend")
57+
__all__.append("Solenoid")
5658

5759

5860
__all__.append("LinacApertureNode")

py/orbit/py_linac/lattice_modifications/errors_modifications_lib.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,8 @@ def restoreFields(self):
485485

486486
def setGaussDistributedRealtiveErrors(self, relative_error, cut_off_level=3.0, comm=mpi_comm.MPI_COMM_WORLD):
487487
"""
488-
Sets the random generated error field for all quads.
488+
Sets the random generated error fields for all quads.
489+
Changes will be different for all quads.
489490
"""
490491
for [quad, field_init] in self.quad_and_field_arr:
491492
rel_err = random.gauss(0.0, relative_error)
@@ -496,6 +497,19 @@ def setGaussDistributedRealtiveErrors(self, relative_error, cut_off_level=3.0, c
496497
field = field_init * (1.0 + rel_err)
497498
quad.setParam("dB/dr", field)
498499

500+
def setGaussDistributedRealtiveErrorToGroup(self,relative_error,cut_off_level = 3.0,comm = mpi_comm.MPI_COMM_WORLD):
501+
"""
502+
Sets the random generated error fields for all quads in the string.
503+
Changes will be the same for all quads. We assume one PS for all quads.
504+
"""
505+
rel_err = random.gauss(0.,relative_error)
506+
while(abs(rel_err) > abs(relative_error)*cut_off_level):
507+
rel_err = random.gauss(0.,relative_error)
508+
main_rank = 0
509+
rel_err = orbit_mpi.MPI_Bcast(rel_err,mpi_datatype.MPI_DOUBLE,main_rank,comm)
510+
for [quad,field_init] in self.quad_and_field_arr:
511+
field = field_init*(1.0 + rel_err)
512+
quad.setParam("dB/dr",field)
499513

500514
class BendFieldNodesModification(ErrorForNodesModification):
501515
"""

py/orbit/py_linac/linac_parsers/sns_linac_lattice_factory.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from orbit.py_linac.lattice import BaseLinacNode, LinacNode, LinacMagnetNode, MarkerLinacNode, Drift, Quad, AbstractRF_Gap, Bend
2121
from orbit.py_linac.lattice import DCorrectorH, DCorrectorV, ThickKick
22+
from orbit.py_linac.lattice import Solenoid
2223
from orbit.py_linac.lattice import RF_Cavity, Sequence
2324
from orbit.py_linac.lattice import BaseRF_Gap
2425

@@ -201,6 +202,12 @@ def positionComp(node_da):
201202
accNode.setnParts(2 * int(accNode.getLength() / self.maxDriftLength + 1.5 - 1.0e-12))
202203
accNode.setParam("pos", node_pos)
203204
accSeq.addNode(accNode)
205+
elif node_type == "SOLENOID":
206+
accNode = Solenoid(node_da.stringValue("name"))
207+
accNode.setParam("B",params_da.doubleValue("B"))
208+
accNode.setLength(node_length)
209+
accNode.setParam("pos", node_pos)
210+
accSeq.addNode(accNode)
204211
# ------------RF_Gap-----------------
205212
elif node_type == "RFGAP":
206213
accNode = BaseRF_Gap(node_da.stringValue("name"))

src/spacecharge/SpaceChargeCalcUnifEllipse.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,12 @@ void SpaceChargeCalcUnifEllipse::bunchAnalysis(Bunch* bunch){
146146
ORBIT_MPI_Allreduce(coord_avg,coord_avg_out,7,MPI_DOUBLE,MPI_SUM,bunch->getMPI_Comm_Local()->comm);
147147

148148
total_macrosize = coord_avg_out[6];
149-
if(total_macrosize == 0.) return;
149+
if(total_macrosize == 0.){
150+
//free resources
151+
OrbitUtils::BufferStore::getBufferStore()->setUnusedDoubleArr(buff_index0);
152+
OrbitUtils::BufferStore::getBufferStore()->setUnusedDoubleArr(buff_index1);
153+
return;
154+
}
150155

151156
//calculate the parameters of the biggest ellipse
152157
x_center = coord_avg_out[0]/total_macrosize;

0 commit comments

Comments
 (0)