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 = 0cancels 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_CAVphase: gaps, field maps (also in aSUPERPOSEcluster) andNCELLS. 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_sclock exists); permissive parses fall back to the legacy end-to-end layout with a warning. - Misalignment and
ERROR_CAVapply cluster-wide, not per child card as TraceWin does (documented divergence; the parser warns when alignment errors land on a container).ADJUSTcards 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/noninvertibleplus 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¶
- TraceWin parity
- PIP-II validation
- Errors directives — what's parsed.
← PIP-II validation · Continue to Convergence checklist →