Overview
This page summarizes the design & implementation of the interface between the live FACET-II controls system and the FACET2E Bmad model.
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.SubprocessTao
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 submit update instructions to a shared queue. Additionally, a daemon thread (model-update) will periodically empty the queue and execute all the scheduled update commands and then update the BmadLiveModel.live
data structure.
Modes of use
The BmadLiveModel can be used 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 model data with manual updates | instanced | f2m = BmadLiveModel(instanced=True) | This mode is designed for making lattice tweaks in Tao relative to extant machine settings |
live model 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 |
Daemon process design
This class makes use of both thread-level and process-level parallelism. Controls system monitoring, processing of update requests and data structure changes are handled asynchronously by callback functions and a model-update
daemon thread. The Tao instance itself is contained in a separate subprocess via pytao.SubprocessTao
. Controls monitoring and device update management are handled asynchronously to optimize performance and minimize delays between changes being broadcast over the network and being mirrored in the model. Tao itself is wrapped in a subprocess for handling Fortran errors, and calls to BmadLiveModel.tao
will still block the main python executable
PV callback functions are responsible for the following actions:
- 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 queue
Separately, the model-update
thread will run forever in a loop, at each iteration it will:
- 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.xcors, live.ycors, live.bends, live.rf
data structures (← or update on request?)
LEM
LEM (LINAC energy management) is responsible for estimating the beam momentum profile pz(s), calculating the corresponding lattice quad settings. The server-side algorithm is as follows:
- calculate the current beam momentum profile, pz_live(s)
start with an estimated momentum profile based on reported klystron amplitudes & phases
- the actual final energy of the beam in each linac is known, given by the spectrometer bend magnet setting. The momentum profile is (approximately) a monotonically increasing function of s between these points
- calculate a "fudge" for each linac (defined as E_estimated / E_design)
- use this value to scale the estimated momentum profile to match the design energies. pz_live(s) = fudge * pz_estimated(s)
- use the live momentum profile to calculate quad settings for the linac
- from design momentum profile:
- calculate a dimensionless "LEM error", pz_err(s) = pz_live(s) / pz_design(s)
- calculate the new magnet BDESes as BDES_LEM = pz_err(s) * BDES_DESIGN, where B_DESIGN is the design value for each quad
- from design multipole coefficients (lcls style)
- get design multipole coefficients (k0_des, k1_des for bends/quads), and magnet lengths l_eff from the model
- calculate the rigidity Brho(s) = pz_live(s) (GeV) / 299.792458e4
- calculate BDES_LEM = Brho * k_des * l_eff
- from design momentum profile:
- publish B_LEM and related PVs to BMAD:SYS0:1:FACET2E:LEM_DATA
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 format of the publish 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, EREF, EACT, BREF, BACT, BERR, more ?? | final data TBD (but single NTTable seems simpler than lcls-style per-device PVs) |
Implementation details
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 |