Overview
This page summarizes the design & implementation of the interface between the live FACET-II controls system and the FACET2E Bmad model. The infrastructure consists of two layers:
BmadLiveModel
: a python class responsible for watching the accelerator and updating a live instance of PyTao based on extant machine settings- The live model PVA service: a process that runs it's own
BmadLiveModel
and publishes data to table PVs - Source code can be viewed on GitHub, and API documentation is available online.
- GitHub mirror: F2_live_model.git
- API documentation: f2-live-model.readthedocs.io/
BmadLiveModel
The goal of this class is to provide access to an instance of Tao
that can view/manipulate the FACET2 Bmad model with settings that match those of the actual production accelerator.
The BmadLiveModel
python class loads the FACET2E lattice and runs a local copy of pytao.Tao
This object connects to the production controls system via EPICS Channel Access, and connects callback functions to each live quantity (PV) of interest. When live quantities change, these callbacks will either (a) submit update instructions to a shared queue or (b) request a recalculation of the live momentum profile by the LEM-watcher
thread. Additionally, a second daemon thread (model-update
) will periodically empty the queue and execute all the scheduled update commands and then update the BmadLiveModel.live and .LEM
data structures.
Modes of use
The BmadLiveModel
operates in three distinct modes, depending on the input flags at construction:
Mode | kw arg | Code snippet | Notes |
---|---|---|---|
design model only | design_only | f2m = BmadLiveModel(design_only=True) | static data only, BmadLiveModel.live is not defined |
live data with manual updates | instanced | f2m = BmadLiveModel(instanced=True) | This mode is designed for making lattice tweaks in Tao relative to extant machine settings. The refresh_all() function is used to update model data. |
live data with real-time streaming | f2m = BmadLiveModel() or: with BmadLiveModel() as f2m: | Use of the context manager is the most pythonic practice, but manual start() and stop() functions are also defined. |
Concurrency design
This class makes use of both async functions (by way of PV callbacks), and thread-based parallelism for controls system monitoring, processing of update requests and data structure changes to optimize performance and minimize delays between changes being broadcast over the network and being mirrored in the model. There are three major concurrent features:
Device Monitoring
Real-time controls-system monitoring is accomplished using PV callback functions.
- RF-related PVs (i.e. klystron ENLDS, phases etc) will request a LEM update, which will trigger the LEM-watcher to recalculate the live momentum profile
- Other PVs (magnet BACTs etc) will directly directly submit the update of a given parameter to a shared queue. To do so, each function must:
- convert the new value into Bmad units (i.e. from kGm → T, GeV → eV etc)
- submit a tuple of
(element name, attribute, value)
to the command queue
LEM-watcher
This thread is responsible for calculating the live beam momentum profile as described below, and submitting update requests for cavity voltages and phases to the command queue.
model-update
This thread is responsible for executing all the submitted update requests using Tao, and to updating derived quantities (BLEM) and python data structures.
- empty the command queue of (approximately*) all submitted updates
- run all the
set ele
commands, then re-calculate lattice parameters - update the
live.p0c, live.e_tot, live.twiss, live.quads, live.bends, live.rf, live.LEM
data structures
LEM
LEM (LINAC energy management) is a set of algorithms responsible for estimating the beam momentum profile and calculating the corresponding lattice quad settings. This code only calculates the momentum profile, errors and magnet settings. Actually setting magnets in the accelerator will be handled by a LEM server GUI (coming soon...).
BmadLiveModel
will monitors the klystron complement and bend magnet settings to calculate the live momentum profile of the beam- Periodically, the server will use the live momentum profile to calculate energy errors and magnet settings, which are published to a table PV
Further notes on LEM: LEM_notes-3.pdf
Calculating the live momentum profile
start by estimating the momentum profile based on reported klystron amplitudes & phases
The estimated momentum profile is unlikely to add up to exactly the correct energy, so we need to scale things by a fudge factor to match reality. Since the actual final energy of the beam in each linac is known form the bend magnet settings, we can calculate this number by comparing the estimated final energy to the actual energy
- under the hood this fudge factor just scales all the cavity voltages in a given region up/down
- the fudge factor will be closer to 1 when ENLDs are current and linac phases are accurate
Calculating magnet settings
calculate relative to design values using a dimensionless "LEM error", i.e. the ratio of the live momentum profile to the design profile
- calculate relative to design values using design multipole coefficients (lcls style)
- get design multipole coefficients (k0_des, k1_des for bends/quads), and (effective) magnet lengths l_eff from the model
calculate the live magnetic rigidity & required field strength (where E_live is in GeV)
calculate relative to extant settings
- note: requires a previously implemented BLEM → if LEM is bootstrapping (i.e. run for the first time without reference to a previous trim) just skip the matching quads
- matching quads should always scale from extant values
F2 Live Model Server
The live model server runs its own BmadLiveModel
, and periodically writes live model data for NTTables accessible on the controls system via EPICS PVAccess. The code for the live model itself is relatively simple, and is derived from the lcls_live_model server.
Access to the live Bmad model server (for twiss/rmat data), should be provided through the python meme
service
The formats of the published tables are as folllows:
PV name | table columns | notes |
---|---|---|
BMAD:SYS0:1:FACET2E:LIVE:TWISS | element, device_name, s, z, length, p0c, alpha_x, beta_x, eta_x, etap_x, psi_x, alpha_y, ..., psi_y | |
BMAD:SYS0:1:FACET2E:LIVE:RMAT | element, device_name, s, z, length, r11, r12, r13, r14, r15, r16, r21, r22, ..., r65, r66 | linear maps from the beginning of the linac to the downstream face of each element |
BMAD:SYS0:1:FACET2E:LIVE:URMAT | element, device_name, s, z, length, r11, r12, r13, r14, r15, r16, r21, r22, ..., r65, r66 | single-element linear maps (i.e. from the upstream to downstream face of each) |
BMAD:SYS0:1:FACET2E:DESIGN:TWISS | element, device_name, s, z, length, p0c, alpha_x, beta_x, eta_x, etap_x, psi_x, alpha_y, ..., psi_y | |
BMAD:SYS0:1:FACET2E:DESIGN:RMAT | element, device_name, s, z, length, r11, r12, r13, r14, r15, r16, r21, r22, ..., r65, r66 | |
BMAD:SYS0:1:FACET2E:DESIGN:URMAT | element, device_name, s, z, length, r11, r12, r13, r14, r15, r16, r21, r22, ..., r65, r66 | |
BMAD:SYS0:1:FACET2E:LEM:DATA | element, device_name, s, z, length, E_ref, E_act, E_err, BLEM, BDES, BDES_SAVE | final data TBD (but single NTTable seems simpler than lcls-style per-device PVs) |
Additionally, the service will publish scalar PVs of the estimated linac amplitudes/chirps/fudges by calculated by LEM. Their names are as follows:
BMAD:SYS0:1:FACET2E:LEM:<XX>_FUDGE
BMAD:SYS0:1:FACET2E:LEM:<XX>_AMPL
BMAD:SYS0:1:FACET2E:LEM:<XX>_CHIRP
where <XX>
is a "LEM region", either L0
, L1
, L2
or L3
, for a total of an additional 12 quantities.
Dependencies
The live model needs to run on the production network (primarily on facet-srv02
)
numpy, spicy
pyEPICS
p4p
Bmad + Tao
Pytao
facet2-lattice
Source files
Source: F2_live_model/ | Details |
---|---|
~/docs/ | config files for sphinx |
~/.readthedocs.yaml | config for readthedocs.io doc generation |
~/structs.py | auxiliary data structures for holding beamline data |
~/bmad.py | implements the BmadLiveModel class |
~/server.py | live model PVA service |