Skip to content

Commit 4ed38fe

Browse files
committed
The method of setUsePhaseAtEntrance(usePhaseAtEntrance = True/False) was added to RF_Cavity class. It defines the place from where the cavity phase is defined. True means at the entrance of the 1st RF gap of the cavity, and False means the center of 1st gap. This parameter is used only for Axis Field RF gaps.
1 parent 7671a02 commit 4ed38fe

File tree

3 files changed

+134
-120
lines changed

3 files changed

+134
-120
lines changed

py/orbit/py_linac/lattice/LinacAccLatticeLib.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,14 @@ def __init__(self, name="none"):
375375
self.addParam("designArrivalTime", 0.0)
376376
self.addParam("isDesignSetUp", False)
377377
self.addParam("pos", 0.0)
378+
#---- This parameter is only for RF gap types with
379+
#---- the continuous RF fields on the axis of the cavity.
380+
#---- If usePhaseAtEntrance = False we will use the phase at the center
381+
#---- of RF gap as for a standard cavity representations as a set
382+
#---- of zero-length RF gaps.
383+
#---- If usePhaseAtEntrance = False we use the phase at the entrance
384+
#---- of the cavity.
385+
self.usePhaseAtEntrance = False
378386

379387
def setDesignSetUp(self, designOnOf):
380388
"""Sets the design set up information (True,False)."""
@@ -482,6 +490,26 @@ def getAvgGapPhase(self):
482490
def getAvgGapPhaseDeg(self):
483491
"""Returns average phase in degrees for all RF gaps in the cavity"""
484492
return self.getAvgGapPhase() * 180.0 / math.pi
493+
494+
def setUsePhaseAtEntrance(self,usePhaseAtEntrance):
495+
"""
496+
This parameter is only for RF gap types with the continuous RF fields
497+
on the axis of the cavity.
498+
If usePhaseAtEntrance = False we will use the phase at the center
499+
of 1 st RF gap as for a standard cavity representations as a set
500+
of zero-length RF gaps.
501+
If usePhaseAtEntrance = False we use the phase at the entrance
502+
of the cavity.
503+
By default it is False. Switching to True will change cavity phase and
504+
all longitudinal dynamics calculations. You should calculate and set
505+
of the cavity phase before the bunch tracking. And, of course, you
506+
should start with the trackDesignBunch(...) lattice method.
507+
"""
508+
self.usePhaseAtEntrance = usePhaseAtEntrance
509+
510+
def getUsePhaseAtEntrance(self):
511+
""" Returns the usePhaseAtEntrance parameter of the cavity """
512+
return self.usePhaseAtEntrance
485513

486514
def removeAllGapNodes(self):
487515
"""Remove all rf gaps from this cavity."""

py/orbit/py_linac/lattice/LinacFieldOverlappingNodes.py

Lines changed: 50 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
# from linac import the RF gap classes
2222
from orbit.core.linac import RfGapThreePointTTF, RfGapThreePointTTF_slow
2323

24+
# import from orbit c++ utilities
25+
from orbit.core.orbit_utils import Function
2426

2527
class AxisField_and_Quad_RF_Gap(AbstractRF_Gap):
2628
"""
@@ -61,8 +63,8 @@ def __init__(self, axis_field_rf_gap):
6163
self.z_step = 0.01
6264
self.z_min = 0.0
6365
self.z_max = 0.0
64-
# ---- gap_phase_vs_z_arr keeps [pos,phase] pairs after the tracking
65-
self.gap_phase_vs_z_arr = []
66+
# ---- gap_pos_phase_func keeps phase=function(pos) after the tracking
67+
self.gap_pos_phase_func = Function()
6668
# ---- The position of the particle during the run.
6769
# ---- It is used for the path length accounting.
6870
self.part_pos = 0.0
@@ -300,16 +302,18 @@ def track(self, paramsDict):
300302
designArrivalTime = rfCavity.getDesignArrivalTime()
301303
phase_shift = rfCavity.getPhase() - rfCavity.getDesignPhase()
302304
phase = rfCavity.getFirstGapEtnrancePhase() + phase_shift
305+
usePhaseAtEntrance = rfCavity.getUsePhaseAtEntrance()
306+
if(usePhaseAtEntrance):
307+
phase = rfCavity.getPhase()
303308
# ----------------------------------------
304309
phase = math.fmod(
305310
frequency * (arrival_time - designArrivalTime) * 2.0 * math.pi + phase,
306311
2.0 * math.pi,
307312
)
308313
if index == 0:
309314
self.part_pos = self.z_min
310-
self.gap_phase_vs_z_arr = [
311-
[self.part_pos, phase],
312-
]
315+
self.gap_pos_phase_func.clean()
316+
self.gap_pos_phase_func.add(self.part_pos, phase)
313317
zm = self.part_pos
314318
z0 = zm + part_length / 2
315319
zp = z0 + part_length / 2
@@ -338,7 +342,7 @@ def track(self, paramsDict):
338342
# call rf gap model to track the bunch
339343
time_middle_gap = syncPart.time() - arrival_time
340344
delta_phase = math.fmod(2 * math.pi * time_middle_gap * frequency, 2.0 * math.pi)
341-
self.gap_phase_vs_z_arr.append([self.part_pos, phase + delta_phase])
345+
self.gap_pos_phase_func.add(self.part_pos, phase + delta_phase)
342346
# ---- this part is the debugging ---START---
343347
# eKin_out = syncPart.kinEnergy()
344348
# s = "debug pos[mm]= %7.2f "%(self.part_pos*1000.)
@@ -377,7 +381,7 @@ def track(self, paramsDict):
377381
self.part_pos += part_length / 2
378382
time_middle_gap = syncPart.time() - arrival_time
379383
delta_phase = math.fmod(2 * math.pi * time_middle_gap * frequency, 2.0 * math.pi)
380-
self.gap_phase_vs_z_arr.append([self.part_pos, phase + delta_phase])
384+
self.gap_pos_phase_func.add(self.part_pos, phase + delta_phase)
381385
# ---- this part is the debugging ---START---
382386
# eKin_out = syncPart.kinEnergy()
383387
# s = "debug pos[mm]= %7.2f "%(self.part_pos*1000.)
@@ -388,29 +392,35 @@ def track(self, paramsDict):
388392
# ---- this part is the debugging ---STOP---
389393
# ---- Calculate the phase at the center
390394
if index == (nParts - 1):
391-
pos_old = self.gap_phase_vs_z_arr[0][0]
392-
phase_gap = self.gap_phase_vs_z_arr[0][1]
393-
ind_min = -1
394-
for ind in range(1, len(self.gap_phase_vs_z_arr)):
395-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
396-
if math.fabs(pos) >= math.fabs(pos_old):
397-
ind_min = ind - 1
398-
phase_gap = self.gap_phase_vs_z_arr[ind_min][1]
399-
phase_gap = phaseNearTargetPhase(phase_gap, 0.0)
400-
self.gap_phase_vs_z_arr[ind_min][1] = phase_gap
401-
break
402-
pos_old = pos
403-
self.setGapPhase(phase_gap)
404-
# ---- wrap all gap part's phases around the central one
405-
if ind_min > 0:
406-
for ind in range(ind_min - 1, -1, -1):
407-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
408-
[pos, phase_gap1] = self.gap_phase_vs_z_arr[ind + 1]
409-
self.gap_phase_vs_z_arr[ind][1] = phaseNearTargetPhase(phase_gap, phase_gap1)
410-
for ind in range(ind_min + 1, len(self.gap_phase_vs_z_arr)):
411-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
412-
[pos, phase_gap1] = self.gap_phase_vs_z_arr[ind - 1]
413-
self.gap_phase_vs_z_arr[ind][1] = phaseNearTargetPhase(phase_gap, phase_gap1)
395+
self._phase_gap_func_analysis()
396+
397+
def _phase_gap_func_analysis(self):
398+
"""
399+
Performs analysis of the RF gap function phase vs. postion
400+
and calculates the accelerating phase at the center of the gap.
401+
"""
402+
n_pos_points = self.gap_pos_phase_func.getSize()
403+
phase_gap = 0.
404+
if(n_pos_points != 0):
405+
phase_gap_old = self.gap_pos_phase_func.y(0)
406+
for pos_ind in range(n_pos_points):
407+
phase_gap = self.gap_pos_phase_func.y(pos_ind)
408+
phase_gap = phaseNearTargetPhase(phase_gap,phase_gap_old)
409+
self.gap_pos_phase_func.updatePoint(pos_ind,phase_gap)
410+
phase_gap_old = phase_gap
411+
phase_gap = self.gap_pos_phase_func.getY(0.)
412+
phase_gap_center = phaseNearTargetPhase(phase_gap,0.)
413+
phase_gap_shift = phase_gap - phase_gap_center
414+
for pos_ind in range(n_pos_points):
415+
phase_gap = self.gap_pos_phase_func.y(pos_ind)
416+
self.gap_pos_phase_func.updatePoint(pos_ind,phase_gap - phase_gap_shift)
417+
self.setGapPhase(phase_gap_center)
418+
419+
def getPhaseVsPositionFuncion(self):
420+
"""
421+
Retuns the RF gap function phase vs. postion.
422+
"""
423+
return self.gap_pos_phase_func
414424

415425
def trackDesign(self, paramsDict):
416426
"""
@@ -433,10 +443,14 @@ def trackDesign(self, paramsDict):
433443
arrival_time = syncPart.time()
434444
frequency = rfCavity.getFrequency()
435445
phase = rfCavity.getFirstGapEtnrancePhase()
446+
usePhaseAtEntrance = rfCavity.getUsePhaseAtEntrance()
447+
if(usePhaseAtEntrance):
448+
phase = rfCavity.getPhase()
436449
# ---- calculate the entance phase
437450
if self.isFirstRFGap() and index == 0:
438451
rfCavity.setDesignArrivalTime(arrival_time)
439-
phase = self.axis_field_rf_gap.calculate_first_part_phase(bunch)
452+
if(not usePhaseAtEntrance):
453+
phase = self.axis_field_rf_gap.calculate_first_part_phase(bunch)
440454
rfCavity.setFirstGapEtnrancePhase(phase)
441455
rfCavity.setFirstGapEtnranceDesignPhase(phase)
442456
rfCavity.setDesignSetUp(True)
@@ -453,9 +467,8 @@ def trackDesign(self, paramsDict):
453467
# print "debug design name=",self.getName()," arr_time=",arrival_time," phase=",phase*180./math.pi," E0TL=",E0TL*1.0e+3," freq=",frequency
454468
if index == 0:
455469
self.part_pos = self.z_min
456-
self.gap_phase_vs_z_arr = [
457-
[self.part_pos, phase],
458-
]
470+
self.gap_pos_phase_func.clean()
471+
self.gap_pos_phase_func.add(self.part_pos, phase)
459472
zm = self.part_pos
460473
z0 = zm + part_length / 2
461474
zp = z0 + part_length / 2
@@ -468,7 +481,7 @@ def trackDesign(self, paramsDict):
468481
# call rf gap model to track the bunch
469482
time_middle_gap = syncPart.time() - arrival_time
470483
delta_phase = math.fmod(2 * math.pi * time_middle_gap * frequency, 2.0 * math.pi)
471-
self.gap_phase_vs_z_arr.append([self.part_pos, phase + delta_phase])
484+
self.gap_pos_phase_func.add(self.part_pos, phase + delta_phase)
472485
# ---- this part is the debugging ---START---
473486
# eKin_out = syncPart.kinEnergy()
474487
# s = "debug pos[mm]= %7.2f "%(self.part_pos*1000.)
@@ -491,7 +504,7 @@ def trackDesign(self, paramsDict):
491504
self.part_pos += part_length / 2
492505
time_middle_gap = syncPart.time() - arrival_time
493506
delta_phase = math.fmod(2 * math.pi * time_middle_gap * frequency, 2.0 * math.pi)
494-
self.gap_phase_vs_z_arr.append([self.part_pos, phase + delta_phase])
507+
self.gap_pos_phase_func.add(self.part_pos, phase + delta_phase)
495508
# ---- this part is the debugging ---START---
496509
# eKin_out = syncPart.kinEnergy()
497510
# s = "debug pos[mm]= %7.2f "%(self.part_pos*1000.)
@@ -502,29 +515,7 @@ def trackDesign(self, paramsDict):
502515
# ---- this part is the debugging ---STOP---
503516
# ---- Calculate the phase at the center
504517
if index == (nParts - 1):
505-
pos_old = self.gap_phase_vs_z_arr[0][0]
506-
phase_gap = self.gap_phase_vs_z_arr[0][1]
507-
ind_min = -1
508-
for ind in range(1, len(self.gap_phase_vs_z_arr)):
509-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
510-
if math.fabs(pos) >= math.fabs(pos_old):
511-
ind_min = ind - 1
512-
phase_gap = self.gap_phase_vs_z_arr[ind_min][1]
513-
phase_gap = phaseNearTargetPhase(phase_gap, 0.0)
514-
self.gap_phase_vs_z_arr[ind_min][1] = phase_gap
515-
break
516-
pos_old = pos
517-
self.setGapPhase(phase_gap)
518-
# ---- wrap all gap part's phases around the central one
519-
if ind_min > 0:
520-
for ind in range(ind_min - 1, -1, -1):
521-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
522-
[pos, phase_gap1] = self.gap_phase_vs_z_arr[ind + 1]
523-
self.gap_phase_vs_z_arr[ind][1] = phaseNearTargetPhase(phase_gap, phase_gap1)
524-
for ind in range(ind_min + 1, len(self.gap_phase_vs_z_arr)):
525-
[pos, phase_gap] = self.gap_phase_vs_z_arr[ind]
526-
[pos, phase_gap1] = self.gap_phase_vs_z_arr[ind - 1]
527-
self.gap_phase_vs_z_arr[ind][1] = phaseNearTargetPhase(phase_gap, phase_gap1)
518+
self._phase_gap_func_analysis()
528519

529520

530521
class OverlappingQuadsNode(BaseLinacNode):

0 commit comments

Comments
 (0)