Time dependent lattice elements
Time dependent lattice elements can be set up when the element is created. This can occur in a variety of situations where elements are driven by time varying sources. This occurs most commonly for rf cavities and induction acceleration gaps, but can also occur in focusing elements with driven excitation. For an rf cavity, harmonic field data from an rf design code might be imported into a 3D field element and then modulated in time with proper phase. For an induction gap, an simple acceleration gap might be driven with the waveform from a pulse power synthesis. For simplicity, here we illustrate the methodology with hard edge focusing elements.
The time dependence can be specified either through a table of data or via a function call. For many elements, the time dependence can be specified in call to the addnewelement functions described in adding new lattice elements. The functions accept time and data arguments, or the func argument. Here is an example of a time dependent electric multipole element that is sinusoidally varying, specified in the two ways. First, with a table of data we take schematically:
fieldtime = span(0.,runtime,ndatapionts) # uniform array of times to specify field
fielddata = fieldamplitude*sin(fieldtime/fieldperiod*2*pi) # array field values at fieldtime
addnewemlt(zs,ze,...,time=fieldtime,data=fielddata) # Lattice element with field data
The time and data arguments should be 1-D arrays. With this, on each time step, the field of the element will be updated based on the table of data. Linear interpolation is applied from nearest data entries if the simulation time is not coincident with entries in the time array.
Second, with a function, we take schematically in the same case as above:
def getfielddata(time):
return fieldamplitude*sin(time/fieldperiod*2*pi)
addnewemlt(zs,ze,...,func=getfielddata)
The getfieldata function takes a single argument, the time, and returns the amplitude at that time.
Note that for some elements there can be multiple field terms and in this case the time dependence needs to be setup separately. For example, for a hard edged quadrupole element, the field can either be electric and/or magnetic. This example shows how to specify a time dependent electric quadrupole.
def getfielddata(time):
return fieldamplitude*sin(time/fieldperiod*2*pi)
iq = addnewquad(zs,ze,de=fieldamplitude)
TimeDependentLatticeElement('quadde',iq,func=getfielddata)
The first argument, 'quadde', specifies the lattice quantity to vary - in this case, the dE/dx of the quadrupole element. One would use 'quaddb' for the magnetic quadrupole. Instead of passing in a function, one could pass in time and data arrays to specify the time dependence. Note that in the first two examples above, the addnewemlt function is calling TimeDependentLatticeElement with 'emltsc' as the first argument.
Another reason to setup the TimeDependentLatticeElement explicitly is that one can get a reference to the object, allowing additional control over it. For example, the time dependence can be disabled at some point during a simulation. For example, if one does:
tdle = TimeDependentLatticeElement('quadde',iq,func=getfielddata)
Then, at some later point in the simulation, one can do
tdle.disable()
to turn off the time dependence. Similarly,
tdle.enable()
can be used to turn back on the time dependence at any point. When the time is disabled, the element will use the amplitude that is originally passed on setup (zero unless user set). In the example able, with de=fieldamplitude.