1+ #--------------------------------------------------------------------
2+ # This script tests the functionality of AxisFieldRF_Gap class.
3+ # It also performs benchmark this calss with the zero-length BaseRfGap() model.
4+ # There are cases:
5+ # =============================================================
6+ # Case 1: Cavity phase scan assuming the phase at z=0 position.
7+ # Case 2: Cavity phase scan assuming the phase at the entrance
8+ # of the cavity
9+ # Case 3: Cavity phase scan with non-empty bunch assuming the phase
10+ # at the entrance of the cavity
11+ # Case 4: Thin (zero length) RF Gap and Axis Field Gap comparison
12+ #---------------------------------------------------------------------
13+
14+ import math
15+ import random
16+ import time
17+ import sys
18+
19+ # from linac import the C++ RF gap classes
20+ from orbit .core .linac import BaseRfGap , MatrixRfGap , RfGapTTF
21+
22+ from orbit .core .bunch import Bunch
23+ from orbit .py_linac .lattice import BaseRF_Gap , AxisFieldRF_Gap , RF_Cavity
24+ from orbit .py_linac .lattice import Drift
25+
26+ from orbit .core .orbit_utils import Function , SplineCH , GaussLegendreIntegrator , Polynomial
27+ from orbit .utils .fitting import PolynomialFit
28+
29+ from orbit .utils import phaseNearTargetPhase
30+ from orbit .utils import phaseNearTargetPhaseDeg
31+
32+ #--------------------------------------------
33+ # Auxiliary Functions
34+ #--------------------------------------------
35+
36+ def getRectangularRfAxisField (z_min ,z_max ):
37+ """
38+ The RF axial field step function normalized to the integral value of 1.
39+ The center position will be assumed at z=0.
40+ """
41+ value = 1. / (z_max - z_min )
42+ npoints = 10
43+ z_step = (z_max - z_min )/ (npoints - 1 )
44+ func = Function ()
45+ for ind in range (npoints ):
46+ z = z_min + z_step * ind
47+ func .add (z ,value )
48+ return func
49+
50+ def transitTimeFactor (bunch ,cav_frequency ,length ):
51+ """
52+ Returns the TTF parameter for the thin RF Gap
53+ with a rectangular axis field.
54+ beta - v/c -relativistic factor
55+ w = cav_frequency [Hz]
56+ L2 = length/2 [m]
57+ lambda = beta*c/w
58+ TTF = lambda/L2*sin((L2/lambda)
59+ """
60+ L2 = length / 2
61+ beta = bunch .getSyncParticle ().beta ()
62+ w = 2 * math .pi * cav_frequency
63+ lmbd = beta * 2.997924e+8 / w
64+ TTF = (lmbd / L2 )* math .sin (L2 / lmbd )
65+ return TTF
66+ #--------------------------------------------
67+ # Script start
68+ #--------------------------------------------
69+
70+ #---- The RF axial field step function normalized to the integral value of 1.
71+ z_min = - 0.1
72+ z_max = 0.1
73+ axis_field_func = getRectangularRfAxisField (z_min ,z_max )
74+
75+ #---- Integral E*L= 20 MeV , here E0L parameter is in GeV
76+ E0L = 0.020
77+ #---- The RF gap object representing one RF gap
78+ accNode = BaseRF_Gap ("BaseRfGap" )
79+ three_point_gap = AxisFieldRF_Gap (accNode )
80+ three_point_gap .setAsFirstRFGap (True )
81+ three_point_gap .setAxisFieldFunction (axis_field_func , z_step = 0.01 )
82+ three_point_gap .setParam ("E0L" , E0L )
83+ #---- mode = 0 - phase as it is, mode = 1 shift phase by +PI
84+ three_point_gap .addParam ("mode" , 1 )
85+
86+ #---- The RF cavity. Here it has only one RF gap
87+ cav_amp = 1.0
88+ cav_frequency = 704.42e6
89+ cav = RF_Cavity ("AxisFieldCavity" )
90+ cav .setAmp (cav_amp )
91+ cav .setFrequency (cav_frequency )
92+ cav .setPosition ((z_min + z_max )/ 2. )
93+ cav .addRF_GapNode (three_point_gap )
94+
95+ #---- At the entrance of ESS spoke.
96+ #---- Kinetic energy and mass in GeV
97+ mass = 0.93827208943
98+ Ekin_init = 0.6201
99+ bunch_init = Bunch ()
100+ bunch_init .mass (mass )
101+ bunch_init .charge (1.0 )
102+ bunch_init .getSyncParticle ().kinEnergy (Ekin_init )
103+
104+ #---- Parameters of the cavity phase scans.
105+ #---- Phases are in radians.
106+ Nph = 72
107+ phase_step = 2 * math .pi / Nph
108+
109+ #--------------------------------------------------------------------
110+ # Case 1: Cavity phase scan assuming the phase at z=0 position.
111+ # We have several types of parameters:
112+ # cav_phase - the input parameter. It is a phase at
113+ # the center of the gap
114+ # cav_1st_gap_entr_phase0 - the phase at the entrance of the 1-st gap
115+ # (we have only one gap) for the cav_phase = 0.
116+ # cav_1st_gap_entr_phase - the phase at the entrance of the 1-st gap
117+ # for the defined cav_phase
118+ # gap_phase - the calculated phase in the center of the RF gap after fitting
119+ # process to get the cav_phase (default accuracy is 0.001 deg)
120+ # delta_phase = cav_1st_gap_entr_phase - cav_phase - cav_1st_gap_entr_phase0
121+ # this phase will be 0 at cav_phase = 0, and it characterizes
122+ # how wrong we are from the realistic phase scan when we
123+ # we define cavity phase at the entrance of the cavity
124+ # delta_eKin_out - the bunch energy gain after acceleration
125+ #--------------------------------------------------------------------
126+ three_point_gap .getRF_Cavity ().setPhase (0. )
127+ bunch = Bunch ()
128+ bunch_init .copyEmptyBunchTo (bunch )
129+ three_point_gap .trackDesignBunch (bunch )
130+ cav_1st_gap_entr_phase0 = three_point_gap .getRF_Cavity ().getFirstGapEtnrancePhase ()
131+
132+ print ("=============================================================" )
133+ print ("Case 1: Cavity phase scan assuming the phase at z=0 position." )
134+ print ("=============================================================" )
135+
136+ st = "CavPhase[deg] CavPhaseErr[deg] DeltaPhase[deg] 1stGapPhase[deg] DeltaE[MeV] "
137+ print (st )
138+
139+ for ind in range (Nph + 1 ):
140+ cav_phase = ind * phase_step
141+ three_point_gap .getRF_Cavity ().setPhase (cav_phase )
142+
143+ bunch = Bunch ()
144+ bunch_init .copyEmptyBunchTo (bunch )
145+ three_point_gap .trackDesignBunch (bunch )
146+
147+ cav_1st_gap_entr_phase = phaseNearTargetPhase (three_point_gap .getRF_Cavity ().getFirstGapEtnrancePhase (),0. )
148+ delta_phase = phaseNearTargetPhase (cav_1st_gap_entr_phase - cav_phase - cav_1st_gap_entr_phase0 ,0. )
149+ gap_phase = phaseNearTargetPhase (three_point_gap .getGapPhase (),cav_phase )
150+ delta_eKin_out = bunch .getSyncParticle ().kinEnergy () - Ekin_init
151+ st = " %+8.2f " % (cav_phase * 180. / math .pi )
152+ st += " %+9.6f " % ((gap_phase - cav_phase )* 180. / math .pi )
153+ st += " %+8.4f " % (delta_phase * 180. / math .pi )
154+ st += " %+8.2f " % (cav_1st_gap_entr_phase * 180. / math .pi )
155+ st += " %+10.6f " % (delta_eKin_out * 1000. )
156+ print (st )
157+
158+
159+ #--------------------------------------------------------------------
160+ # Case 2: Cavity phase scan assuming the phase at the entrance
161+ # of the cavity
162+ # We have several types of parameters:
163+ # cav_phase - the input parameter. It is a phase at
164+ # the center of the gap
165+ # cav_1st_gap_entr_phase0 - the phase at the entrance of the 1-st gap
166+ # (we have only one gap) for the cav_phase = 0.
167+ # cav_1st_gap_entr_phase - the phase at the entrance of the 1-st gap
168+ # for the defined cav_phase
169+ # gap_phase - the calculated phase in the center of the RF gap after fitting
170+ # process to get the cav_phase (default accuracy is 0.001 deg)
171+ # delta_phase = cav_1st_gap_entr_phase - cav_phase - cav_1st_gap_entr_phase0
172+ # this phase will be 0 at cav_phase = 0, and it characterizes
173+ # how wrong we are from the realistic phase scan when we
174+ # we define cavity phase at the entrance of the cavity
175+ # delta_eKin_out - the bunch energy gain after acceleration
176+ #--------------------------------------------------------------------
177+
178+ #---- Set the cavity property
179+ three_point_gap .getRF_Cavity ().setUsePhaseAtEntrance (True )
180+
181+ three_point_gap .getRF_Cavity ().setPhase (0. )
182+ bunch = Bunch ()
183+ bunch_init .copyEmptyBunchTo (bunch )
184+ three_point_gap .trackDesignBunch (bunch )
185+ cav_1st_gap_entr_phase0 = three_point_gap .getRF_Cavity ().getFirstGapEtnrancePhase ()
186+
187+ print ("=============================================================" )
188+ print ("Case 2: Cavity phase scan assuming the phase at the entrance." )
189+ print ("=============================================================" )
190+
191+ st = "CavPhase[deg] CavPhaseErr[deg] DeltaPhase[deg] 1stGapPhase[deg] DeltaE[MeV] "
192+ print (st )
193+
194+ for ind in range (Nph + 1 ):
195+ cav_phase = ind * phase_step
196+ three_point_gap .getRF_Cavity ().setPhase (cav_phase )
197+
198+ bunch = Bunch ()
199+ bunch_init .copyEmptyBunchTo (bunch )
200+ three_point_gap .trackDesignBunch (bunch )
201+
202+ cav_1st_gap_entr_phase = phaseNearTargetPhase (three_point_gap .getRF_Cavity ().getFirstGapEtnrancePhase (),0. )
203+ delta_phase = phaseNearTargetPhase (cav_1st_gap_entr_phase - cav_phase - cav_1st_gap_entr_phase0 ,0. )
204+ gap_phase = phaseNearTargetPhase (three_point_gap .getGapPhase (),cav_phase )
205+ delta_eKin_out = bunch .getSyncParticle ().kinEnergy () - Ekin_init
206+ st = " %+8.2f " % (cav_phase * 180. / math .pi )
207+ st += " %+8.4f " % ((gap_phase - cav_phase )* 180. / math .pi )
208+ st += " %+8.2f " % (delta_phase * 180. / math .pi )
209+ st += " %+8.2f " % (cav_1st_gap_entr_phase * 180. / math .pi )
210+ st += " %+10.6f " % (delta_eKin_out * 1000. )
211+ print (st )
212+
213+ #--------------------------------------------------------------------
214+ # Case 3: Cavity phase scan with non-empty bunch assuming the phase
215+ # at the entrance of the cavity.
216+ # We have several types of parameters:
217+ # cav_phase - the input parameter. It is a phase at
218+ # the center of the gap
219+ # delta_eKin_out - the bunch energy gain after acceleration
220+ # (x,xp,y,yp,z,dE) - 6D coordinates of the particle
221+ #--------------------------------------------------------------------
222+
223+ #---- Set the cavity property
224+ three_point_gap .getRF_Cavity ().setUsePhaseAtEntrance (True )
225+
226+ three_point_gap .getRF_Cavity ().setPhase (0. )
227+ bunch = Bunch ()
228+ bunch_init .copyEmptyBunchTo (bunch )
229+ three_point_gap .trackDesignBunch (bunch )
230+
231+ print ("=============================================================" )
232+ print ("Case 3: Cavity phase scan with one particle in the bunch." )
233+ print ("=============================================================" )
234+
235+ st = "CavPhase[deg] DeltaE[MeV] x[mm] xp[mrad] y[mm] yp[mrad] z[mm] dE[MeV] "
236+ print (st )
237+
238+ for ind in range (Nph + 1 ):
239+ cav_phase = ind * phase_step
240+ three_point_gap .getRF_Cavity ().setPhase (cav_phase )
241+
242+ bunch = Bunch ()
243+ bunch_init .copyBunchTo (bunch )
244+ bunch .addParticle (0.01 ,0. ,0.01 ,0. ,0. ,0. )
245+
246+ three_point_gap .trackBunch (bunch )
247+
248+ delta_eKin_out = bunch .getSyncParticle ().kinEnergy () - Ekin_init
249+ st = " %+8.2f %+8.4f " % (cav_phase * 180. / math .pi ,delta_eKin_out * 1000. )
250+ st += " %8.3f %+8.3f " % (bunch .x (0 )* 1000. ,bunch .xp (0 )* 1000. )
251+ st += " %8.3f %+8.3f " % (bunch .y (0 )* 1000. ,bunch .yp (0 )* 1000. )
252+ st += " %8.3f %+8.3f " % (bunch .z (0 )* 1000. ,bunch .dE (0 )* 1000. )
253+ print (st )
254+
255+ print ("====================================================================" )
256+ print ("Case 4: Thin (zero length) RF Gap and Axis Field Gap comparison" )
257+ print ("====================================================================" )
258+ TTF = transitTimeFactor (bunch_init ,cav_frequency ,z_max - z_min )
259+ print ("Zero-length RF Gap: Transit Time Factor TTF=" ,TTF )
260+
261+ base_rf_gap = BaseRF_Gap ("BaseRfGap" )
262+ base_rf_gap .setParam ("E0TL" , E0L * TTF )
263+ #---- setting RF gap tracker
264+ base_rf_gap .setCppGapModel (BaseRfGap ())
265+
266+ #---- The RF cavity for zero-length RF gap. Here it has only one RF gap
267+ cav_amp = 1.0
268+ cav_frequency = 704.42e6
269+ cav_base = RF_Cavity ("BaseGapCavity" )
270+ cav_base .setAmp (cav_amp )
271+ cav_base .setFrequency (cav_frequency )
272+ cav_base .setPosition ((z_min + z_max )/ 2. )
273+ cav_base .addRF_GapNode (base_rf_gap )
274+
275+ #---- Tracking design for both types of RF gaps
276+ base_rf_gap .getRF_Cavity ().setPhase (0. )
277+ bunch = Bunch ()
278+ bunch_init .copyEmptyBunchTo (bunch )
279+ base_rf_gap .trackDesignBunch (bunch )
280+
281+ three_point_gap .getRF_Cavity ().setPhase (0. )
282+ bunch = Bunch ()
283+ bunch_init .copyEmptyBunchTo (bunch )
284+ three_point_gap .trackDesignBunch (bunch )
285+
286+ #---- drifts before and after zero-length RF gap
287+ drift_before = Drift ("drift_before" )
288+ drift_before .setLength ((z_max - z_min )/ 2 )
289+ drift_after = Drift ("drift_after" )
290+ drift_after .setLength ((z_max - z_min )/ 2 )
291+
292+ print ("==== 0 - for zero-length and 1 - for axis field RF gap ====" )
293+ st = "CavPhase[deg] deltaE_0[MeV] deltaE_1[MeV] delta_0-1[MeV] delta_phase_0-1[deg]"
294+ print (st )
295+
296+ for ind in range (Nph + 1 ):
297+ cav_phase = ind * phase_step
298+ base_rf_gap .getRF_Cavity ().setPhase (cav_phase )
299+ three_point_gap .getRF_Cavity ().setPhase (cav_phase )
300+
301+ bunch = Bunch ()
302+ bunch_init .copyBunchTo (bunch )
303+ drift_before .trackBunch (bunch )
304+ base_rf_gap .trackBunch (bunch )
305+ drift_after .trackBunch (bunch )
306+ delta_eKin_out_0 = bunch .getSyncParticle ().kinEnergy () - Ekin_init
307+ exit_phase0 = (bunch .getSyncParticle ().time ()* cav_frequency )* 180. / math .pi
308+ exit_phase0 = phaseNearTargetPhaseDeg (exit_phase0 ,0. )
309+
310+ bunch = Bunch ()
311+ bunch_init .copyBunchTo (bunch )
312+ three_point_gap .trackBunch (bunch )
313+ delta_eKin_out_1 = bunch .getSyncParticle ().kinEnergy () - Ekin_init
314+ exit_phase1 = (bunch .getSyncParticle ().time ()* cav_frequency )* 180. / math .pi
315+ exit_phase1 = phaseNearTargetPhaseDeg (exit_phase1 ,exit_phase0 )
316+
317+ delta_phase = exit_phase0 - exit_phase1
318+
319+ st = " %+8.2f " % (cav_phase * 180. / math .pi )
320+ st += " %+8.4f " % (delta_eKin_out_0 * 1000. )
321+ st += " %+8.4f " % (delta_eKin_out_1 * 1000. )
322+ st += " %+8.4f " % ((delta_eKin_out_0 - delta_eKin_out_1 )* 1000. )
323+ st += " %+8.4f " % delta_phase
324+
325+ print (st )
326+
327+
328+ print ("Stop." )
329+ sys .exit (0 )
0 commit comments