Input File Generation (Command-Line Mode)
Introduction
PASS uses JSON files as simulation input. The engine ( Config , Beam , CommandSequence ) reads all parameters from the JSON file, including particle species, bunch distribution, lattice sequence, monitors, etc.
The parameter system PASS/para/ provides a set of schema definitions based on pydantic v2 . Users assemble parameter objects through Python scripts and call generate_input() to output an engine-compatible JSON file. Compared to hand-writing JSON, this approach offers the following advantages:
Type safety : Parameter types and ranges are declared in the schema; invalid values are intercepted at generation time;
Alias mapping : Python code uses concise property names (e.g.,
circumference), while the JSON output automatically uses the keys expected by the engine (e.g.,"Circumference (m)");Reusability : Schema objects can be quickly derived via
model_copy(update={...}), suitable for parameter scans;GUI support : Typed schemas also support the graphical configuration workflow.
Note
This document introduces input file generation in command-line mode. For the graphical workflow, see Graphical configuration workflow.
Architecture Overview
The parameter system is divided into five layers, each with clear responsibilities and no inter-dependencies:
PASS/para/
├── schema/ Parameter definitions (single source of truth)
│ ├── main.py MainConfig: global simulation parameters
│ ├── bunch.py BunchConfig + OffsetConfig + InjectionItem
│ ├── twiss.py TwissPoint: twiss transfer point
│ ├── elements.py 12 element types (Drift→RFCavity)
│ ├── monitors.py StatMonitor / DistMonitor / PhaseAdvanceMonitor
│ ├── space_charge.py SpaceChargeConfig + SpaceChargeResourceConfig + SpaceCharge
│ └── sequence.py Sequence: ordered container + auto-sorting
├── madx.py MADX TFS → schema objects (element / twiss / error)
├── smooth.py Analytical smooth approximation twiss
├── tools/ External data → PASS TFS
│ ├── data_converter.py General data conversion pipeline
│ ├── ramping.py Element ramping file generation
│ ├── rf_data.py RF data file generation
│ └── exciter_data.py Exciter data file generation
├── toolkit.py sort_sequence + class_map + apply_element_settings + build_sequence
└── api.py High-level API (generate_input / load_input / generate_from_tfs)
The data flow is as follows:
MADX TFS / user parameters / external data files
│
▼
madx.py / smooth.py + tools/ → schema objects / TFS files
│
▼
schema/ (pydantic) ← single source of truth: validation + aliases
│
▼
api.py (generate_input) → beam0.json
│
▼
PASS engine (Config → Beam → CommandSequence → Executor)
Quick Start
Minimal Example
The following script generates a complete input file containing injection + smooth approximation twiss + statistical monitor:
from PASS.para.api import generate_input
from PASS.para.schema.main import MainConfig
from PASS.para.schema.bunch import BunchConfig, InjectionItem
from PASS.para.schema.sequence import Sequence
from PASS.para.schema.monitors import StatMonitor
from PASS.para.smooth import generate_smooth_twiss
# 1. Global parameters
main = MainConfig(
beam_name="proton",
num_proton=1, num_neutron=0, num_electron=1,
gamma_t=4.8, circumference=251.327,
num_turns=1000, backend="cpu",
)
# 2. Bunch
bunch = BunchConfig(
kinetic_energy=45e6,
num_real_particles=int(1e11),
num_macro_particles=int(1e5),
beta_x=0.5, beta_y=0.5,
alpha_x=-2.61, alpha_y=1.57,
emit_x=200e-6, emit_y=100e-6,
sigma_z=30, dp=0.005,
dist_trans="gaussian", dist_longi="matchz",
rf_voltage=100e3, rf_phase=0.5236,
)
# 3. Lattice sequence
items, circum = generate_smooth_twiss(
circumference=main.circumference,
qx=4.8, qy=4.4, num_points=100,
)
main.circumference = circum
seq = Sequence()
seq.add("injection", InjectionItem(s=0.0, random_seed=2026, bunches=[bunch]))
for i, item in enumerate(items):
seq.add(f"twiss_{i:04d}", item)
seq.add("stat1", StatMonitor(s=0.0))
# 4. Generate JSON
generate_input(main, seq, "beam0.json")
How to run:
cd C:\Users\changmx\Documents\PASS
python input/generate_beam0.py
Output file: input/beam0.json
JSON File Structure
The generated JSON file has the following structure:
{
"Beam Name": "proton",
"Number of Protons": 1,
"Number of Neutrons": 0,
"Number of Charges": 1,
"Transition Gamma": 4.8,
"Circumference (m)": 251.327,
"Number of turns": 1000,
"Backend (gpu/cpu)": "cpu",
"Number of GPU devices": 1,
"Device Id": [0],
"Output directory": "./output",
"Is plot figure": true,
"Is beam-beam": false,
"Sequence": {
"injection": {
"S (m)": 0.0,
"Command": "Injection",
"Harmonic Number": 1,
"Random Seed": 2026,
"bunch0": {}
},
"twiss_0000": {
"S (m)": 0.0,
"Command": "Twiss",
"S previous (m)": 0.0,
"Beta x (m)": 8.333
},
"stat1": {
"S (m)": 0.0,
"Command": "StatMonitor"
}
}
}
Note
The JSON key names are a hard contract of the engine. The schema layer automatically handles the mapping from Python property names to JSON keys through pydantic’s alias mechanism; users do not need to write them manually.
When reading, the engine first calls convert_keys_to_lower() to convert all keys to lowercase, so the case of JSON keys does not affect reading.
Core Components
MainConfig (Global Parameters)
Property |
JSON key |
Type |
Description |
|---|---|---|---|
|
|
str |
Beam label |
|
|
int |
Number of protons per particle (0 for electron/positron) |
|
|
int |
Number of neutrons per particle (>0 for ions) |
|
|
int |
Number of charges per particle (can be negative, cannot be 0) |
|
|
float |
Transition gamma |
|
|
float |
Ring circumference (m) |
|
|
int |
Number of simulation turns |
|
|
str |
Compute backend: |
|
|
int |
Number of GPUs |
|
|
list[int] |
GPU device ID list |
|
|
str |
Output directory |
|
|
bool |
Whether to generate plots |
|
|
bool |
Whether to enable beam-beam interaction |
Space charge is configured by the separate top-level Space charge block,
not by MainConfig. See Space-Charge Effect (SpaceCharge) for its named resource schema
and sequence-command references. Each resource selects Method (pic,
frozen, quasi-frozen) and Solver; the latter includes the boundary
condition in its name. The command’s Aperture type/value defines particle
losses and, for Dirichlet solvers, the conducting wall. Configurations no longer
contain Chamber. Supply a complete grid full-width or half-width pair;
omitting the command aperture selects a rectangle equal to that grid.
InjectionItem (Injection and Grouping)
InjectionItem declares harmonic_number (JSON key Harmonic Number) once at the injection level. This value is the bunch-grouping count and determines:
The number of bunch centers around the ring, separated by \(C/h_{\mathrm{group}}\)
The required number of
BunchConfigentries inbunchesThe requirement that
harmonic_idvalues uniquely cover \(0,\ldots,h_{\mathrm{group}}-1\)
It does not constrain RFCavityElement.harmonic. Represent an unfilled group with a declared bunch whose num_macro_particles is zero.
Set random_seed (JSON key Random Seed) to an integer when the generated particle distribution must be reproducible. Leave it unset, or use JSON null, for the default non-deterministic seed. The seed belongs to the whole Injection command, so its random stream is shared by all declared bunches and injection turns.
BunchConfig (Bunch Parameters)
Property |
JSON key |
Type |
Description |
|---|---|---|---|
|
|
float |
Kinetic energy per nucleon (eV/u) |
|
|
int |
Number of real particles per bunch |
|
|
int |
Number of macro particles per bunch |
|
|
float |
Twiss β function |
|
|
float |
Twiss α function |
|
|
float |
Emittance |
|
|
float |
Bunch length |
|
|
float |
Momentum spread |
|
|
str |
Transverse distribution: |
|
|
str |
Longitudinal distribution: |
|
|
float |
RF voltage (used in matchz/matchdp modes) |
|
|
float |
RF phase |
|
|
int |
Bunch-group index; its center is \(z_{\mathrm{center}}=h_{\mathrm{id}}C/h_{\mathrm{group}}\) |
|
|
float |
RF-cavity position relative to injection, used to linearly back-propagate a matched distribution to \(s=0\) |
|
|
float |
Mean bunch relative-momentum offset; mutually exclusive with the kinetic-energy offset |
|
|
float |
Mean bunch kinetic-energy offset, converted exactly to a relative-momentum offset internally |
All generated or manually inserted z values in BunchConfig are bunch-relative coordinates \(z_{\mathrm{rel}}\), not absolute laboratory azimuths.
Sequence (Sequence Container)
Sequence is an ordered container that stores all sequence items arranged by position s . The order of insertion does not affect the final result — items are automatically sorted by (s, command priority) upon export.
seq = Sequence()
seq.add("injection", InjectionItem(s=0.0, bunches=[bunch]))
seq.add("qd1", QuadrupoleElement(s=1.0, k1l=0.2, length=0.5))
seq.add("stat1", StatMonitor(s=0.0))
Supported sequence item types:
InjectionItem— injection point (must haves=0)TwissPoint— twiss transfer pointDriftElement,QuadrupoleElement,SBendElement, etc. — physical elementsStatMonitor,DistMonitor,PhaseAdvanceMonitor— monitors
Lattice Sources
PASS supports three methods for generating lattice sequences, which can be selected or combined as needed:
Method 1: Read from MADX twiss file
Reads a twiss TFS file generated by MADX, converting each element into a TwissPoint transfer point. Suitable for element-by-element twiss transport mode.
from PASS.para.madx import read_madx_twiss
items, names, circum = read_madx_twiss(
twiss_file="lattice.tfs",
error_file="errors.tfs", # optional
muz=0.001, # longitudinal tune
dqx=0.0, # chromaticity (or "from_file")
dqy=0.0,
is_field_error=False, # whether to read field errors
insert_patterns=["QD.*"], # regex matching, inserted as thin lens elements
)
For a uniform base grid, use the resampling reader instead:
from PASS.para.madx import read_madx_twiss_interpolated
items, names, circum = read_madx_twiss_interpolated(
twiss_file="lattice.tfs",
num_interp_slice=101, # 100 segments, including both 0 and C
dqx="from_file", dqy="from_file",
longitudinal_transfer="off",
)
This reader uses interp_kind="phase_hermite" (the sole supported method),
replacing the former independent cubic-column interpolation and extrapolation.
num_interp_slice counts base points, not segments; it must be an integer
at least two. DQx/DQy now default to "from_file" and Mu z defaults to zero.
The longitudinal phase is used only for longitudinal_transfer="matrix".
In each source interval of length \(h\), define \(t=(s-s_i)/h\) and interpolate \(p(t)=\mu(s)-\mu(s_i)\) with a quintic Hermite polynomial. The endpoint constraints, in phase cycles, are:
The interpolated optical functions are:
This preserves \(\beta'=-2\alpha\) and \(\mu'=1/(2\pi\beta)\) within each interval, while matching source beta, alpha and cumulative phase at its endpoints. The full phase derivative is checked at its endpoints and all interior extrema to exclude nonpositive beta. DX/DPX use paired cubic Hermite interpolation in the existing uncoupled, on-reference paraxial convention; their TFS normalization is retained. No new coupling or closed-orbit coordinate conversion is introduced. Source precision and spacing limit accuracy.
The table must include S=0 and S=LENGTH, with finite optics, positive beta and unwrapped phases. Its full phase spans must agree with Q1/Q2 within TFS output rounding (relative tolerance \(2\times10^{-8}\), absolute tolerance \(2\times10^{-9}\)). Output phases retain the source values rather than being rescaled to rounded headers. Segment chromaticities are distributed in proportion to the source phase span, preserving the requested DQx/DQy sums.
Original rows are not retained as additional output points. Matched thin elements, field errors and repeated-S optical jumps add required split positions. Error names are matched against the original table before resampling. At optical jumps, a zero-length Twiss map joins the incoming and outgoing states. Additional kicks/errors execute after the Twiss maps at that position, consistent with command priority. Explicitly inserting design focusing already represented by the source optics adds it again; error insertion does not preserve the perturbed machine’s tune by construction. See Graphical configuration workflow for the corresponding import controls.
Method 2: Read from MADX twiss file as elements
Reads the twiss file, but converts each element into its corresponding physical element object ( QuadrupoleElement , SBendElement , etc.). Suitable for element-by-element tracking mode.
from PASS.para.madx import read_madx_elements
items, names, circum = read_madx_elements(
twiss_file="lattice.tfs",
is_merge_drift=True, # merge adjacent drift sections
is_field_error=True,
error_file="errors.tfs",
)
Method 3: Smooth approximation twiss
No MADX file required; uses analytical formulas to generate twiss points with constant β function. \(\beta = C / (2\pi Q)\) . Suitable for quick testing.
from PASS.para.smooth import generate_smooth_twiss
items, circum = generate_smooth_twiss(
circumference=569.1,
qx=9.47, qy=9.43,
num_points=100,
muz=0.001,
)
Mixed Mode
Twiss transfer points and physical elements can be mixed within the same sequence. For example, inserting an RF cavity into a twiss sequence:
from PASS.para.schema.elements import RFCavityElement
seq = Sequence()
seq.add("injection", InjectionItem(s=0.0, bunches=[bunch]))
# twiss transfer points
for i, item in enumerate(twiss_items):
seq.add(f"twiss_{i:04d}", item)
# insert RF cavity (at s=0)
seq.add("rf1", RFCavityElement(s=0.0, voltage=100e3, harmonic=1, phase=0.5236))
External Data File Conversion
PASS uses the TFS format as the unified format for all ramping/RF/exciter data files. tools/data_converter.py provides a general conversion pipeline that transforms various external files (CSV/TXT/TFS) into PASS TFS.
Four-Step Pipeline
External file → load_raw_data → time_to_turn → interpolate → write_tfs
load_raw_data : Reads the external file, auto-detects turn/time columns
time_to_turn : If the external file provides time instead of turns, converts using the revolution frequency
interpolate_to_continuous_turns : Automatically interpolates when turns are non-contiguous
write_tfs_ramping : Writes to the PASS unified TFS format
One-Step Conversion
from PASS.para.tools.data_converter import convert_external_to_tfs
convert_external_to_tfs(
input_path="external_ramp.csv", # external file
output_path="k1l_ramping.tfs", # PASS TFS
data_cols=["k1l", "k1sl"], # data column names
revolution_freq=1.76e6, # revolution frequency (Hz)
num_turns=5000, # target number of turns
method="linear", # interpolation method
)
Pre-packaged Wrappers
Thin wrappers for common element types:
from PASS.para.tools.ramping import convert_k1l_ramping, convert_k2l_ramping
from PASS.para.tools.rf_data import convert_rf_data
# Quadrupole ramping
convert_k1l_ramping("external.csv", "k1l_ramping.tfs", revolution_freq=1.76e6)
# RF data
convert_rf_data("llrf.csv", "rf_data.tfs", revolution_freq=1.76e6)
Step-by-Step Invocation
When the external file format is non-standard, each function can be called step by step:
from PASS.para.tools.data_converter import (
interpolate_to_continuous_turns, write_tfs_ramping,
)
import numpy as np
# Prepare data manually
turn_arr = np.array([1, 50, 100, 500, 1000])
k2l = np.array([0.0, 0.5, 1.0, 2.5, 4.4])
turn_cont, data_cont = interpolate_to_continuous_turns(
turn_arr, {"K2L": k2l},
start_turn=1, end_turn=1000, method="linear",
)
write_tfs_ramping("k2l_ramping.tfs", turn_cont, None, data_cont)
API Reference
from PASS.para.api import (
build_sequence, generate_from_tfs, generate_input, load_input,
)
# Assemble a sequence with a reproducible Injection distribution
sequence = build_sequence(
items=items,
names=names,
bunches=bunches,
monitors=monitors,
random_seed=2026,
)
# The high-level MADX helper accepts the same Injection seed
generate_from_tfs(
twiss_file="lattice.tfs",
output_path="beam0.json",
main=main_dict,
bunches=bunch_dicts,
random_seed=2026,
)
# Generate JSON
generate_input(
main: MainConfig,
sequence: Sequence,
output_path: str,
space_charge: SpaceChargeConfig | None = None,
extra_modules: dict | None = None,
) -> str
# Load existing JSON (for modification and regeneration)
main, seq_dict = load_input("beam0.json")
Complete Example
The built-in example script is located at input/generate_beam0.py and can be run directly:
cd C:\Users\changmx\Documents\PASS
python input/generate_beam0.py
This script demonstrates the complete end-to-end workflow: global parameters → multi-bunch configuration → smooth approximation twiss → lattice sequence assembly → JSON output. The generated beam0.json can be directly read and executed by the PASS engine.