Skip to content

KLYS support - #64

Merged
eloise-nebula merged 7 commits into
mainfrom
klys_db
Aug 10, 2026
Merged

KLYS support#64
eloise-nebula merged 7 commits into
mainfrom
klys_db

Conversation

@williamColocho

Copy link
Copy Markdown
Collaborator

Title: Consolidate klystron sub-cavity rows and add KLYS accessor support

Summary

Oracle's lcls_elements.csv stores each klystron station as four separate
sub-cavity rows (e.g. K21_5A, K21_5B, K21_5C, K21_5D) all sharing the
same EPICS cs_name (KLYS:LI21:51). This PR consolidates those into one row
per station (K21_5) in lcls_elements.sqlite3 and propagates that through to
device.sqlite3, aligning the database representation with how lcls-live
identifies and addresses klystron stations.

It also adds a KLYS: accessor block to accessor_names.yaml so that the
standard KLYS PV suffixes (ENLD, PHAS, PDES, etc.) are mapped to
developer-friendly names, and introduces klystron_metadata.yaml to encode
per-station PV overrides for the nine stations that deviate from the normal
KLYS:LI{sector}:{station}1:{SUFFIX} pattern (GUN, L0A, L0B, L1S, L1X,
K24_1/2/3, and K26_3).

Motivation

lcls-live's KlystronDataMap models one entry per station. Having four rows
per station in device.sqlite3 caused redundant entries, made beampath and
accessor lookups ambiguous, and prevented klystrons from receiving correct PV
accessor assignments during the database build.

Changes

slac_db/create/lcls_elements.py

  • _Parser._parse_csv(): added sub-cavity deduplication. For any LCAV row
    whose element name ends in A-D and whose cs_name contains KLYS, the
    trailing letter is stripped to form the canonical station name (e.g.
    K21_5A -> K21_5). Only the first encountered sub-cavity per station is
    kept; subsequent ones are discarded. The dedup key is the station name rather
    than the cs_name, which makes it robust against dirty data in the source CSV
    (two stations in sectors 12-19 have truncated or digit-transposed cs_names:
    K12_3A has LI12:KLYS:3 instead of LI12:KLYS:31, and K17_8C has
    LI17:KLYS:18 instead of LI17:KLYS:81).
  • Handles both cs_name orderings found in the CSV:
    • Modern: KLYS:LI{sector}:{station}1 (sectors 20-30)
    • Legacy: LI{sector}:KLYS:{station}1 (sectors 12-19)

slac_db/package_data/accessor_names.yaml

  • Added a KLYS: device type block mapping the ten standard KLYS PV suffixes
    to accessor names that match lcls-live's KlystronDataMap field names:

    PV suffix accessor name
    ENLD energy_gain
    PHAS phase
    PACT phase_actual
    PDES phase_desired
    BEAMCODE1_STAT beamcode1
    BEAMCODE2_STAT beamcode2
    SWRD swrd
    STAT stat
    HDSC hdsc
    DSTA dsta

slac_db/package_data/klystron_metadata.yaml (new file)

Follows the pattern of wire_metadata.yaml. Encodes per-station PV overrides
for the nine stations that cannot be expressed by the normal KLYS accessor
pattern. Two categories:

  1. Entirely different PV bases — no KLYS: prefix; all amplitude and phase
    PVs are overridden and fault/beamcode PVs are set to absent (''):

    • K20_6 — GUN klystron (GUN:IN20:1:GN1_*)
    • K20_7 — L0A injector linac (ACCL:IN20:300:L0A_*_DS{n}, beamcode-dependent)
    • K20_8 — L0B injector linac (ACCL:IN20:400:L0B_*_DS{n}, beamcode-dependent)
    • K21_1 — L1S sub-booster (ACCL:LI21:1:L1S_*_DS{n}, beamcode-dependent)
    • K21_2 — L1X 3rd-harmonic linearizer (ACCL:LI21:180:L1X_*_DS{n}, beamcode-dependent)
  2. Normal KLYS base, phase PV overridden only (beamcode-specific):

    • K24_1ACCL:LI24:100:KLY_PDES:SETDATA_{bc}
    • K24_2ACCL:LI24:200:KLY_PDES:SETDATA_{bc}
    • K24_3ACCL:LI24:300:KLY_PDES:SETDATA_{bc}
  3. Always disabled:

    • K26_3 — mothballed klystron; in_use: false, no fault or beamcode PVs

slac_db/metadata.py

  • Added get_klystron_metadata() following the get_wire_metadata() pattern.
    Reads klystron_metadata.yaml and returns a flat dict per station mapping
    accessor names to PV addresses. Beamcode-specific sub-dicts (beamcode1,
    beamcode2) are expanded with a suffix, e.g. phase_act_pvname under
    beamcode1 becomes the accessor name phase_actual_beamcode1.

slac_db/create/combined.py

  • _Parser._accessor_meta(): klystron stations have keyword=LCAV in Oracle
    (shared with TCAVs). The accessor lookup now checks whether KLYS appears
    in the cs_name and uses "KLYS" as the accessor map key in that case,
    ensuring the new KLYS: block in accessor_names.yaml is applied.
  • Added _Parser._apply_klystron_accessor_overrides(): called after the normal
    accessor build, reads get_klystron_metadata() and replaces accessor entries
    for the special stations with the correct override PV addresses. Empty
    overrides (absent PVs) are removed from the accessors table entirely.

Result

After rebuilding lcls_elements.sqlite3 then device.sqlite3:

  • 321 sub-cavity rows (K21_5A/B/C/D style) are collapsed to 84 station rows
    across areas L1, L1F, L2, L2F, L3, LI25, matching the lcls-live station list.
  • Each klystron station in device.sqlite3 carries the correct accessor set,
    e.g. for a normal station (K21_5):
    energy_gain, phase, phase_actual, phase_desired,
    beamcode1, beamcode2, swrd, stat, hdsc, dsta
  • K24_1/2/3 carry additional beamcode-specific phase accessors:
    phase_actual_beamcode1, phase_desired_beamcode1,
    phase_actual_beamcode2, phase_desired_beamcode2
  • K26_3 carries no fault or beamcode accessors (always disabled).

Rebuild steps required

@eloise-nebula eloise-nebula left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including Klystrons in the device database leads to some interesting exceptions that we haven't had to deal with before. We'll have to discuss more in detail. I think some of these issues could be resolved with better integration with a device class.

My main comment is that the klystron_metadata interface inserts exception PVs after the fact. I think that's something that we could include in the accessor_names.yaml by using a "private" key like _overrides to store a dictionary of devices with known exceptions.

Comment thread slac_db/create/combined.py Outdated
Comment thread slac_db/create/combined.py
Comment thread slac_db/package_data/klystron_metadata.yaml Outdated
Comment thread slac_db/metadata.py Outdated
Comment thread slac_db/package_data/accessor_names.yaml Outdated
Comment thread slac_db/package_data/accessor_names.yaml
Comment thread slac_db/create/combined.py
Comment thread slac_db/create/combined.py

@eloise-nebula eloise-nebula left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you William! This solution looks great and provides a nice interface for anyone else who wants to use the same pattern to do their own overrides.

Approving, but make sure you remove/edit the get_klystron_metadata function that references a file that doesn't exist anymore.

Comment thread slac_db/metadata.py Outdated
@eloise-nebula
eloise-nebula merged commit d7f0db8 into main Aug 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants