2121# from linac import the RF gap classes
2222from orbit .core .linac import RfGapThreePointTTF , RfGapThreePointTTF_slow
2323
24+ # import from orbit c++ utilities
25+ from orbit .core .orbit_utils import Function
2426
2527class 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
530521class OverlappingQuadsNode (BaseLinacNode ):
0 commit comments