Skip to content

Known limitations & deferred features

A complete list of what HELIX deliberately doesn't do, what's parsed-but-not-honoured, and what's on the roadmap. Useful for deciding whether HELIX is the right tool for a given project.

Out of scope (deferred)

Time-varying / dynamic errors

TraceWin's ERROR_*_DYN directives apply per-step random jitter inside the tracker hot loop. The dynamic semantics are not implemented — note the parser does not skip these cards: it absorbs them as ordinary static NCPL errors (one draw per seed).

  • Why deferred: adds RNG calls at every integration step (significant performance hit) and physics complication.
  • Workaround: static per-seed errors cover ~95 % of real workflows. Multi-seed ensembles approximate the dynamic case.

Coupled (CPL) error groups

ERROR_*_CPL_* directives apply the same random draw to a group of elements (e.g. a triplet sharing a power supply). The coupled semantics are not implemented — as with _DYN, the parser absorbs these cards as uncoupled static errors (independent draw per element) rather than skipping them.

  • Why deferred: needs a "group pattern" extension to ErrorDef that wasn't in the initial scope.
  • Workaround: implement the group draw manually in Python.

Element-error slots without tracking effect: dz, pitch, yaw

dz (longitudinal alignment) and φx/φy (pitch/yaw) draws are stored on the element, but the tracker only honours dx, dy and tilt_deg. The parser now emits a warning when an ERROR_* card declares a non-zero value for any of them, so a tolerance that has no effect is at least visible.

(Fixed 2026-07: voltage_rel on FieldMap/FieldMap3D cavities and field_rel on Dipole — formerly silent no-ops — are now applied via the elements' own _rel slots. Re-run pre-fix tolerance studies that used cavity amplitude or bend-field errors.)

See Element-level errors.

No longitudinal normal mode for a lattice with bends

Since 2026-09-07 a bend couples the transverse and longitudinal planes through its path-length row, which is correct physics — and it means the 2×2 (Δφ, ΔW) block of such a lattice is no longer its longitudinal mode. compute_twiss(M, "z") therefore raises ValueError ("coupled to plane z") for any lattice containing a bend, at the default coupling_tol=1e-8; a BTL cell reaches an off-plane sum of 7.4e-3 and the MEBT-to-foil line 5.8e-1. Extracting the true mode would require transforming the dispersion away first, which HELIX does not do.

Nothing that used to be reported is lost. Across the twenty shipped decks — every period detect_periods finds, twenty-nine of them with a bend, plus every whole-lattice matrix — μ_x, μ_y, μ_z and β_z are identical before and after: 157 values equal, none gained, none lost. The reason is that a bend-containing period in a transport line has a shear longitudinal block (M₄₄ = M₅₅ = 1, M₅₄ = 0), so cos μ = 1 and it was already refused as unstable; only the message changed. The tolerance can only bite where a period holds RF and a bend, which no shipped deck does. Passing coupling_tol= explicitly still returns the projected 2×2 value for callers who want it knowing what it is — that is what linac_gen/analysis/phase_advance.py does at its coupled-lattice call sites. Pinned in tests/tracking/test_path_length_row.py::test_compute_twiss_z_refuses_a_bend_lattice_and_offers_the_projection.

A second consequence: the reported longitudinal emittance through a dispersive region is a projection of a genuinely correlated distribution and grows sharply — ×10.7 on examples/bend_line.dat for a 100 MeV proton with no current and the BeamConfig defaults for the rest, and the factor depends on the input beam — while the six-dimensional phase-space volume is conserved, because the map is symplectic. Read such a number together with the symplecticity check in the same test file before reporting a blow-up.

Tilt misalignments in matrix-mode analyses

Since 2026-09-06 the composed transfer matrix (compute_transfer_matrix, i.e. matrix mode, run --mode matrix, the periodic-Twiss solve of the whole line), the dispersion-along-s walk and the phase-advance walk all conjugate every element's matrix by its tilt_deg, as the multi-particle tracker, the envelope solver and the torch matrix path always did. The cell-wise periodic dispersion (matching/periodic.py) still calls get_element_matrix directly and sees each element untilted. Nominal lattices carry no tilt_deg, so only error studies that inspect that quantity are affected.

Commands in the matrix walks

Matrix mode and the phase-advance and dispersion walks apply FREQ and the HELIX energy card (; HELIX_SET_ENERGY, ; HELIX_SHIFT_ENERGY), as the envelope and multiparticle modes do. Ring mode skips the energy card, with a warning. SET_BEAM_ENERGY and SET_BEAM_E0_P0 are matching criteria, as in TraceWin: they change nothing in tracking. A MAD-X export holds one reference energy: it writes the energy card as a comment, with a warning.

SET_BEAM_PHASE_ERROR

As the TraceWin manual defines it, the card leaves the beam's phase alone and shifts the RF phase of the cavities after it. With Dp, each following cavity's beam sees its phase Dp later; with random_flag, a draw within ±Dp that an error study makes per seed (a plain run shifts nothing, with a warning). Dp = 0 starts the cavities after it afresh: the shifts before it end, and in an error study the cavities that see the arrival (field maps with p_flag 0, NCELLS with P = 1, a gap held at a pinned clock) take the seed's correction. That correction is the error-free arrival at the card minus the seed's, along one reference walk from where the beam starts (a .dst file's header, for a beam read from one), so a seed without errors gets exactly none. HELIX's relative-phase cavities re-phase to the reference every run and need no correction. A seed keeps its draw and its correction: pulse jitter on a frozen seed and a reliability campaign's transport carry them, and pulse jitter on a lattice no error study has stamped fixes its cards first (no correction, one draw). Where HELIX differs from TraceWin:

  • The design includes the cards: Dp = 0 cancels the phase error the seed's errors gave the beam (a random draw counts as one), not an earlier card's deliberate shift.
  • The correction is set when the seed is drawn. What changes the machine afterwards is not corrected: pulse-to-pulse jitter (dynamic, as in TraceWin), and a fault that a reliability campaign puts on a seed, which is then treated as the same fault alone.
  • An input-beam error that moves the bunch centroid is not cancelled (one that moves the reference is); HELIX treats dynamic errors as static, so they are.
  • The card corrects the phase at its own position: a beam off energy goes on slipping over a drift after it.
  • The cavities that follow it are those that take an ERROR_CAV phase: gaps, field maps (also in a SUPERPOSE cluster) and NCELLS. An RFQ does not, and an engaged surrogate does not follow the shift yet.

A continuous beam's Δφ is not rescaled at a FREQ card in a multiparticle run; a transfer matrix holds the factor regardless. Nothing reads a continuous beam's z block.

Dipole.e1 / e2 act on the full-element matrix only

The pole-face angles stored on a Dipole are added as thin-lens edge matrices when the element's full transfer matrix is requested (matrix mode, the envelope solver's element step). The multi-particle tracker and the envelope space-charge sub-stepping slice the bend body and never apply them. Lattices read from .dat, MAD-X, MAD8 or Elegant files are unaffected — their pole faces are separate Edge elements, honoured in every mode — so only Python-built lattices that set e1/e2 directly see a mode-dependent difference. Use Edge elements for mode-independent optics.

SUPERPOSE_MAP v1 scope

Straight-axis field-map superposition is implemented (SuperposedFieldMap, 2026-07). Three deliberate v1 restrictions remain:

  • SUPERPOSE_MAP_OUT (dipole maps that curve the reference trajectory) is modelled since 2026-10 as a curved cluster, with its own limits: static magnetic 3-D maps only; no backtracking, Sacherer envelope, torch matrix path, ring mode or MAD-X export; θX / θZ placements follow the TraceWin manual's figure, which no example run pins (the parser warns).
  • Mixed RF frequencies in one cluster are refused at construction (a single ref.phi_s clock exists); permissive parses fall back to the legacy end-to-end layout with a warning.
  • Misalignment and ERROR_CAV apply cluster-wide, not per child card as TraceWin does (documented divergence; the parser warns when alignment errors land on a container). ADJUST cards targeting a container are warn-skipped.

Binary 2-D Cartesian field maps are refused

TraceWin binary field maps are read for the 1-D, 2-D cylindrical and 3-D Cartesian layouts the TraceWin manual documents. The manual gives no binary layout for the 2-D Cartesian map, so such a file is refused with an error rather than decoded by guesswork; use its ASCII version. The GUI's add-element-from-file path (the legacy reader) decodes binary 3-D maps and refuses binary 1-D / 2-D files with the same advice.

Labels with spaces are not written back

The parser accepts labels containing spaces (SOL 1 : SOLENOID …) and keeps them as element.label, but write_tracewin emits only labels without whitespace or colons, so a saved deck drops a spaced label. Label-only lines (HWR CM:) add no element and are not written back.

A field-free card with a missing map is written back as a drift

A FIELD_MAP card with kb = ke = Ki = Ka = 0 whose map files are missing is kept as its length only (a drift, or the span of its SUPERPOSE_MAP cluster), so a saved deck carries a DRIFT in its place. A SHIFT_IN_FIELD_MAP diagnostic bound to such a card is restored at the card position with a warning; one whose offset falls in the part of a cluster covered only by such a card is dropped with a warning.

Written .dat field-map paths are absolute

write_tracewin records field-map file locations as absolute paths, so a saved .dat that references FIELD_MAP files is not portable to another machine or directory tree — re-point the field map folder (or edit the paths) after moving a project.

Periodic-Twiss helpers omit dispersion

find_periodic_twiss and find_matched_input_twiss solve the 4-D/6-D betatron problem only — they do not carry dispersion. For lattices with bends (BTL arcs, HEBT) use find_sc_matched_input_twiss, which matches dispersion through an 8-state formulation. See Matching → Python API.

Envelope mode: apertures and MIN_TRANSMISSION are inert

Envelope (RMS) tracking propagates Σ only — no particles means no aperture cuts, so transmission is implicitly 100 % and the MIN_TRANSMISSION matching constraint is silently inert (a one-time stderr warning is printed). Use cost_solver="mp" for loss-sensitive matching, and multi-particle runs for any loss prediction. See SET / ADJUST → MIN_TRANSMISSION.

ML surrogates accelerate 0 mA envelope runs only (plus opted-in MP)

A registered surrogate engages on the envelope solver's pure-linear path — current = 0, no per-sub-step recording, no SHIFT_IN_FIELD_MAP interior markers — where the solver requests exactly the full-element matrix the network was trained on. SC-active envelope runs (current > 0) and per-sub-step walks request partial slices of the field map, and a linear end-to-end matrix cannot be cut into honest sub-slices of a time-varying RF field, so those requests always delegate to the wrapped RK4: zero NN queries, zero speedup, results bit-identical to the unregistered run. The compare report, CLI and GUI all print the NN query count so a registered-but-idle surrogate is visible. Multi-particle engagement requires the explicit double opt-in (see the surrogates chapter). A slice-aware surrogate is roadmap work.

ADJUST_STEERER auto-correction (now shipped)

Implemented as of 2026-05-09. TraceWin's closed-orbit auto- correction loop is now driven by :func:linac_gen.errors.correction.run_correction_from_lattice, which scans the lattice for ADJUST_STEERER / ADJUST_STEERER_BX / ADJUST_STEERER_BY cards and pairs each with a DIAG_POSITION (BPM) marker via the diag_n index.

Picks one-to-one when the cardinality is 1:1 and pairing is clean, otherwise SVD with truncated pseudoinverse. Honours vmax per card as a per-steerer T·m clip. See Errors → Orbit correction.

vmax-units convention: the max field on ADJUST_STEERER is interpreted as an integrated kick in T·m on the partner Steerer.bx_l / Steerer.by_l, since HELIX steerers are zero-length thin kicks. Magnetic-steerer Bmax in the STEERER card itself uses the same convention.

Dead-beam detection is MP-only: the corrector refuses to declare convergence when any used BPM reads a dead beam (recorded transmission 0 — see the dead-beam contract), but the envelope reading backend tracks no apertures and its results carry no transmission, so a correction computed with reading_backend="envelope" can still be one that loses a real beam. Verify envelope-backend corrections with a multi-particle run.

ERROR_RFQ_CEL_NCPL_STAT

Per-cell RFQ electrode displacements. Niche; deferred.

Wakefields

  • Longitudinal wake — bunch-induced longitudinal field.
  • Transverse wake — bunch-induced kicks in subsequent bunches.
  • Resistive-wall wake — image-charge / pipe-current effects.

None modelled. For a proton/H⁻ linac they're typically a small correction; for high-power accumulators they're critical and HELIX is not the right tool.

Image-charge / pipe-current effects

Open-boundary PIC; the beam pipe is just an aperture cut, not a boundary condition for the Poisson solve.

Synchrotron radiation damping

Irrelevant for the proton-linac use case (proton SR is negligible below ~100 GeV). Relevant for high-energy electron storage rings — HELIX is not the right tool.

Coupling beyond linear

Transverse-longitudinal coupling beyond first-order dispersion / phase-slip mixing. Higher-order coupling (e.g. chromatic-dispersion in a strong dipole) is not modelled.

Acceleration in Sacherer ODE

The Sacherer continuous-beam envelope solver assumes constant β, γ. RF cavities aren't supported in that path — for accelerated beams use the matrix tracker plus bunched PIC SC.

Pitch / yaw misalignment

Misalignment mixin reserves pitch_deg and yaw_deg slots, but the tracker only honours tilt_deg (rotation about z). Pitch / yaw are non-symplectic in 4-D tracking and need the longitudinal coordinate to absorb the path-length change — separate work.

Parsed-but-not-honoured

Field Status
Quadrupole.gfr parsed, no effect (TraceWin: gradient-fall-region)
pitch_deg, yaw_deg reserved on every element; only tilt_deg is honoured
geom = 8 (3-D cylindrical field map) parsed, but TraceWin manual says "not implemented"

PIC results and the thread count (resolved 2026-10-11)

Until 2026-10-11 the C++ CIC deposit added per-thread partial sums, so changing the OpenMP thread count shifted results in the last digits. It now adds every cell's contributions in particle order, and every kernel, the FFT and both deposits give the same bits for any thread count, so results no longer depend on it — see CPU threads. Results files written before then record omp_num_threads and omp_schedule in provenance/.

Backtracking through CSR is approximate (opt-in)

CSR kicks have no backward model. run_backtrack() on a forward run with csr_enabled=True refuses unless you pass approximate_backtracking=True, which skips the CSR kicks on the backward walk and warns that the reconstruction is approximate. The same contract applies to sc_backend="halo" (2026-07): the learned defect corrector has no backward model, so the backward walk refuses unless approximate_backtracking=True accepts the plain-PIC undo.

Release-hardening tasks (accepted as such in review, 2026-07)

Two deliberate deferrals, neither a correctness defect in current behavior:

  • Surrogate lookup uses the resolved field-file path, not a content hash — an in-place edit of a field-map file (same path, same length, same geometry) would not be caught by the cross-lattice engagement guard. The planned hardening replaces the path with the SHA-256 already computed for HDF5 provenance.
  • Backtracking returns no machine-readable status enum — the exact/linearized/approximate/non-invertible distinctions are all enforced by refusals and warnings (and the CLI prints a human-readable forward-closure check), but callers cannot yet branch on which reversal mode actually ran. The planned ledger: exact_discrete_replay / linearized_inverse / approximate_collective_replay / noninvertible plus a per-element fallback list.

Calibration biases (not bugs, known offsets)

  • PIC kernel — ~3 % σ overshoot vs TraceWin partran on PIP-II. See PIP-II validation.
  • Longitudinal σ_z — ~22 % overshoot in HELIX vs TW. Cause not localised.

Roadmap

Items being actively considered (no commitments):

  • Dynamic errors (per-step RNG).
  • Wakefield infrastructure (longitudinal first).
  • Per-step density / time-domain recording for sub-element diagnostics.
  • Pitch / yaw misalignment (needs 6-D rather than 4-D tracker tweaks).
  • Higher-order (3-D) field-map coupling.
  • PDF rendering of this manual.

For requests / status updates see GitHub issues.

Cross-references

← PIP-II validation · Continue to Convergence checklist →