API Reference
All public symbols are re-exported from the top-level albums package and
documented below in their defining submodule.
Submodules
albums.mbtrack2_to_pycolleff
Module with conversion function to go from mbtrack2 to pycolleff.
- synchrotron_to_pycolleff(synchrotron, I0, Vrf, bunch_number)[source]
Return a pycolleff Ring element from the synchrotron element data.
- Parameters
synchrotron (mbtrack2.tracking.synchrotron.Synchrotron) – Parameters description.
I0 (float) – Beam current in [A].
Vrf (float) – RF voltage in [V].
bunch_number (int) – Total number of bunches filled.
- Returns
ring – pycolleff Ring object.
- Return type
pycolleff.colleff.Ring
- cavityresonator_to_pycolleff(cavres, Impedance=True)[source]
Convenience method to export a CavityResonator to pycolleff.
- Parameters
cavres (mbtrack2.tracking.rf.CavityResonator) – CavityResonator object.
Impedance (bool, optional) – If True, export as impedance (i.e. ImpedanceSource.Methods.ImpedanceDFT). If False, export as wake (i.e. ImpedanceSource.Methods.Wake). Default is True.
- Returns
cav
- Return type
pycolleff ImpedanceSource object
- impedance_to_pycolleff(impedance)[source]
Convenience method to export impedance to pycolleff. Only implemented for longitudinal impedance.
- Parameters
impedance (mbtrack2.impedance.wakefield.Impedance) – Impedance object.
- Returns
imp – pycolleff ImpedanceSource object
- Return type
pycolleff.longitudinal_equilibrium.ImpedanceSource
albums.optimiser
Module where the optimization functions are defined.
- _require_r_factor(flow) None[source]
Reject flows whose equilibrium does not compute a meaningful R-factor.
- evaluate_R(B: SystemState, flow, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), is_equilibrium: bool = False) float[source]
Evaluate the R-factor (or the equilibrium-only R-factor) of one operating point as a score to be minimised.
- Parameters
B (SystemState) – The system to evaluate.
flow (Flow) – Flow object used for solving.
eq_opts (EquilibriumOptions) – Beam current, integration boundary and solver options.
theory_opts (TheoryOptions) – Shared theory inputs (used only when is_equilibrium is False).
is_equilibrium (bool) – If True, evaluate the equilibrium only (no instability theories). The score is then only penalised for non-convergence. If False, it is also penalised at any unstable operating point, and at any point where a theory failed to converge.
- Returns
Negative R-factor if successful and stable, a penalty (10) otherwise.
- Return type
float
- maximize_R(ring: Synchrotron, cavity_list: list[CavityResonator], flow, psi0_HC: float, bounds, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts: OptimiserOptions = OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), is_equilibrium: bool = False) float[source]
Optimise the harmonic-cavity tuning angle to maximise the R-factor.
- Parameters
ring (Synchrotron) – Ring configuration.
cavity_list (list of CavityResonator) – Main cavity in position 0, the harmonic cavity (whose psi is optimised) in position 1.
flow (Flow) – Solve flow.
psi0_HC (float) – Initial guess for the harmonic-cavity tuning angle in degrees.
bounds (tuple) – (lower, upper) bounds for the tuning angle.
eq_opts (EquilibriumOptions) – Beam current, integration boundary and solver options.
theory_opts (TheoryOptions) – Shared theory inputs (used only when is_equilibrium is False).
opti_opts (OptimiserOptions) – scipy and loop settings of the optimisation.
is_equilibrium (bool) – If True, optimise the equilibrium-only R-factor (no instability theories).
- Returns
Optimal tuning angle in degrees, or 90 on failure.
- Return type
float
- Raises
IncompatibleFlowError – If the flow’s equilibrium does not provide a meaningful R-factor (Capability.TOUSCHEK_LIFETIME_RATIO), e.g. a Bosch flow.
- _get_vals(ring: Synchrotron, cavity_list: list[CavityResonator], flow, psi0_HC: float, bounds, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts: OptimiserOptions = OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), is_equilibrium: bool = False) tuple[source]
Optimise psi_HC then return (psi, Result) at the chosen operating point.
Drives maximize_R, optionally seeding the initial guess from xi_init_input (auto_psi_input) and, when loop_option is set, stepping psi outward until a stable point is found. is_equilibrium selects equilibrium-only solving and the matching stability check.
albums.options
Typed option objects for the ALBuMS pipeline:
EquilibriumOptions : everything that defines a beam-equilibrium solve.
TheoryOptions : the run-time inputs shared by the instability theories.
OptimiserOptions : the settings of the tuning-angle optimisation.
ScanOptions : grid-evaluation settings for scans.
PlotOptions : display settings for the 2D scan and optimisation plots.
- class EquilibriumOptions(I0: float | None = None, tau_boundary: float | None = None, passive_harmonic_cavity: bool = True, auto_set_MC_theta: bool = True, optimal_tunning: bool = True, max_counter: int = 200, auto_set_for_xi: bool = False, xi: float | None = None, F_init: Any = None, set_MC_phase_HCpassive: bool = False, niter: int = 200, tol: float = 1e-08, beta: float = 0.1, m: int = 3, print_flag: bool = False, filling: Any = None, impedance: Any = None)[source]
Bases:
objectEverything that defines a beam-equilibrium solve.
- Variables
solver) (**Common options** (read by every equilibrium) –
I0 (float or None) – Beam current in [A]. None until set; SystemState raises if a solve is attempted while it is still None.
tau_boundary (float or None) – Half-window in [s] for the potential and form-factor integrals. If None, 0.1 times the RF period (0.1 * ring.T1) is used.
passive_harmonic_cavity (bool) – If True the harmonic cavity is treated as passive (beam-driven); if False as active (generator-driven).
auto_set_MC_theta (bool) – If True the main-cavity synchronous phase is set automatically from the energy loss before solving. Not read by the active-Bosch solver, which derives the main-cavity phase from xi instead (see auto_set_for_xi).
optimal_tunning (bool) – If True the harmonic-cavity detuning is set to its optimal value for the target bunch lengthening before solving.
specific** (**Alves) –
max_counter (int) – Maximum number of fixed-point iterations of the Bosch form-factor loop.
specific** –
auto_set_for_xi (bool) – If True the cavity settings are chosen to reach the requested force ratio xi instead of being used as given.
xi (float or None) – Target main-to-harmonic force ratio used when auto_set_for_xi is True.
specific** –
F_init (array-like or None) – Initial guess for the per-cavity amplitude form factor. None starts from all ones.
set_MC_phase_HCpassive (bool) – If True, correct the main-cavity phase in the passive-harmonic-cavity case when the beam losses exceed the main-cavity voltage.
specific** –
niter (int) – Maximum number of iterations of the self-consistent equilibrium loop.
tol (float) – Convergence tolerance on the form factor for the self-consistent loop.
beta (float) – Under-relaxation factor between 0 and 1 damping each update step of the loop.
m (int) – Number of azimuthal harmonics kept in the form-factor expansion.
print_flag (bool) – If True, print convergence diagnostics during the loop.
filling (array-like or None) – Filling pattern (per-bucket current weights); None means uniform filling.
impedance (object or None) – Additional longitudinal impedance source or sources added to the cavity impedances; None for cavities only.
- I0: float | None = None
- tau_boundary: float | None = None
- passive_harmonic_cavity: bool = True
- auto_set_MC_theta: bool = True
- optimal_tunning: bool = True
- max_counter: int = 200
- auto_set_for_xi: bool = False
- xi: float | None = None
- F_init: Any = None
- set_MC_phase_HCpassive: bool = False
- niter: int = 200
- tol: float = 1e-08
- beta: float = 0.1
- m: int = 3
- print_flag: bool = False
- filling: Any = None
- impedance: Any = None
- __init__(I0: float | None = None, tau_boundary: float | None = None, passive_harmonic_cavity: bool = True, auto_set_MC_theta: bool = True, optimal_tunning: bool = True, max_counter: int = 200, auto_set_for_xi: bool = False, xi: float | None = None, F_init: Any = None, set_MC_phase_HCpassive: bool = False, niter: int = 200, tol: float = 1e-08, beta: float = 0.1, m: int = 3, print_flag: bool = False, filling: Any = None, impedance: Any = None) None
- class TheoryOptions(mode_coupling: bool = True, f_HOM: float | numpy.ndarray = 0, Z_HOM: float | numpy.ndarray = 0)[source]
Bases:
objectRun-time inputs shared by the instability theories.
- Variables
specific** (**HOMCoupledBunch) –
mode_coupling (bool) – If True the zero-frequency stability test includes mode coupling. Pair False with a flow using the no-coupling Robinson theory.
specific** –
f_HOM (float or array-like) – Higher-order-mode resonant frequency or frequencies in [Hz] for the coupled-bunch theory. 0 disables the HOM.
Z_HOM (float or array-like) – Shunt impedance or impedances of the HOM in ohms.
- mode_coupling: bool = True
- f_HOM: float | numpy.ndarray = 0
- Z_HOM: float | numpy.ndarray = 0
- __init__(mode_coupling: bool = True, f_HOM: float | numpy.ndarray = 0, Z_HOM: float | numpy.ndarray = 0) None
- class OptimiserOptions(method_opti: str = 'COBYLA', tol_opti: float = 0.01, maxiter_opti: int = 1000, rhobeg_opti: float = 0.1, method: str = 'Nelder-Mead', tol: float = 0.05, loop_option: bool = False, add_psi_loop: float = 0.02, max_loop: int = 200, auto_psi_input: bool = False, xi_init_input: float = 0.8, debug: bool = False)[source]
Bases:
objectSettings for the harmonic-cavity tuning-angle optimisation.
- Variables
method_opti (str) – scipy.optimize.minimize method for the R-factor maximisation.
tol_opti (float) – Convergence tolerance for the R-factor maximisation.
maxiter_opti (int) – Maximum number of iterations for the R-factor maximisation.
rhobeg_opti (float) – Initial COBYLA step size (rhobeg) for the R-factor maximisation.
method (str) – scipy.optimize.minimize method for the psi minimisation.
tol (float) – Convergence tolerance for the psi minimisation.
loop_option (bool) – If True, after the optimisation step the tuning angle outward until a stable operating point is found.
add_psi_loop (float) – Increment in degrees applied to the tuning angle on each iteration of the stabilisation loop.
max_loop (int) – Maximum number of stabilisation-loop iterations before giving up.
auto_psi_input (bool) – If True, derive the initial tuning-angle guess from xi_init_input instead of the supplied initial guess.
xi_init_input (float) – Target force ratio used to derive the initial tuning-angle guess when auto_psi_input is True.
debug (bool) – If True, print optimisation diagnostics.
- method_opti: str = 'COBYLA'
- tol_opti: float = 0.01
- maxiter_opti: int = 1000
- rhobeg_opti: float = 0.1
- method: str = 'Nelder-Mead'
- tol: float = 0.05
- loop_option: bool = False
- add_psi_loop: float = 0.02
- max_loop: int = 200
- auto_psi_input: bool = False
- xi_init_input: float = 0.8
- debug: bool = False
- __init__(method_opti: str = 'COBYLA', tol_opti: float = 0.01, maxiter_opti: int = 1000, rhobeg_opti: float = 0.1, method: str = 'Nelder-Mead', tol: float = 0.05, loop_option: bool = False, add_psi_loop: float = 0.02, max_loop: int = 200, auto_psi_input: bool = False, xi_init_input: float = 0.8, debug: bool = False) None
- class ScanOptions(skip: bool = False)[source]
Bases:
objectGrid-evaluation settings for the parameter and optimisation scans.
These control how the grid is swept, not what is plotted (see PlotOptions).
- Variables
skip (bool) – If True, stop scanning a row early once grid points stop converging. Saves time on regions that are uniformly non-physical.
- skip: bool = False
- __init__(skip: bool = False) None
- class PlotOptions(contour: bool = True, title: bool = True, axes: Any = None, colorbar: bool = True, cbar_v: tuple = (None, None), show_legend: bool = True, n_contour: int = 15, marker_size: float = 80, alpha: float = 0.7, manual_clabel: bool = False, colorplot: bool = True, contour_alpha: float = 1, contour_linestyles: str = '-', cmap: str = 'viridis', log_color: bool = False, save: bool = False)[source]
Bases:
objectDisplay settings for the 2D scan and optimisation plots.
Every knob has a documented default in one place.
- Variables
contour (bool) – If True, overlay contour lines on the colour map.
title (bool) – If True, set the axes title to the scan name.
axes (matplotlib.axes.Axes or None) – Existing axes to draw on; None creates a new figure and axes.
colorbar (bool) – If True, draw the colour bar.
cbar_v (tuple of (float or None, float or None)) – The (vmin, vmax) colour-map limits; (None, None) auto-scales.
show_legend (bool) – If True, draw the instability-marker legend.
n_contour (int) – Number of contour levels.
marker_size (float) – Scatter marker size for instability flags.
alpha (float) – Scatter marker transparency.
manual_clabel (bool) – If True, place contour labels interactively.
colorplot (bool) – If True, draw the filled colour map (set False for contour-only plots).
contour_alpha (float) – Contour line transparency.
contour_linestyles (str) – Contour line style.
cmap (str) – Matplotlib colour map name for the background image.
log_color (bool) – If True, log-normalise the background colour map via matplotlib LogNorm (cbar_v sets the LogNorm limits). Only strictly positive data is shown; use for quantities spanning orders of magnitude (e.g. growth rates).
save (bool) – If True, write the figure to a PNG named from the scan and flow.
- contour: bool = True
- title: bool = True
- axes: Any = None
- colorbar: bool = True
- cbar_v: tuple = (None, None)
- show_legend: bool = True
- n_contour: int = 15
- marker_size: float = 80
- alpha: float = 0.7
- manual_clabel: bool = False
- colorplot: bool = True
- contour_alpha: float = 1
- contour_linestyles: str = '-'
- cmap: str = 'viridis'
- log_color: bool = False
- save: bool = False
- __init__(contour: bool = True, title: bool = True, axes: Any = None, colorbar: bool = True, cbar_v: tuple = (None, None), show_legend: bool = True, n_contour: int = 15, marker_size: float = 80, alpha: float = 0.7, manual_clabel: bool = False, colorplot: bool = True, contour_alpha: float = 1, contour_linestyles: str = '-', cmap: str = 'viridis', log_color: bool = False, save: bool = False) None
albums.plot_func
Module with the core plotting functions.
- configure_plot(ax=None, title=None, xlabel=None, ylabel=None, grid=True, legend=True)[source]
Helper function to configure plot appearance.
- save_plot(name, label, plot_2D, tau_boundary=None)[source]
Helper function to save plots with consistent naming.
- create_grid(var1, var2, var1_unit, var2_unit)[source]
Helper function to create grids and scaled variables.
- plot_image(ax, data, extent, clabel, var1_grid, var2_grid, cmap='viridis', vmin=None, vmax=None, norm=None, colorbar=True, contour=False, colorplot=True, contour_dict={})[source]
Helper function to handle 2D data visualization.
- _as_result_array(out)[source]
A ResultArray from either a ResultArray or a raw results_to_arrays dict.
- _aggregate_growth(ra)[source]
Most-unstable growth rate at each grid point, reduced over every theory in the result that carries a growth rate.
- _theory_growth(ra, spec)[source]
(data, label) for a per-theory growth quantity.
spec is “<theory_name>” or “<theory_name>:<mode>”. Growth is read straight from the theory’s own storage (ra.theories[name]) and masked to the points where that theory (or the selected mode) flags an instability.
- _background_data(ra, quantity)[source]
The (data, colour-bar label) for one background quantity.
Equilibrium quantities (“xi”, “bunch_length”, “Touschek”) and the optimiser-only “psi” map read the flow-agnostic categories. Growth quantities are keyed on the theory name: “growth” gives the most-unstable map across all theories, while “growth_<theory_name>” (optionally “growth_<theory_name>:<mode>”) reads one theory’s growth rate, masked where it flags an instability.
- _robinson_markers(unstable, coupled)[source]
(mask, marker, label, color) tuples for a Robinson-family theory’s 4 modes.
- _instability_markers(ra)[source]
Yield (mask, marker, label, color) for every instability the result holds.
Driven by the theories actually present in ra.theories, so the plot reflects the flow, and multiple theories of the same physical category (for example two PTBL theories) each get their own marker for benchmarking.
- _equilibrium_not_converged_mask(ra)[source]
Points where the Stage-1 equilibrium solve itself failed (no theory ran).
- _theory_not_converged_mask(ra)[source]
Points where the equilibrium converged but some theory’s own convergence check (root-finder) failed, and no theory flags an instability there (so the point isn’t already decisively explained, e.g. by zero-frequency instability).
- plot_scan(out, var1, var2, var1_unit, var2_unit, var1_label, var2_label, quantity, plot_opts=None, name=None, flow='', tau_boundary=None)[source]
Plot one background quantity over the 2D scan grid and overlay every instability the flow produced.
- Parameters
out (ResultArray or dict) – The scan result.
var1 (numpy.ndarray) – Scan axes (outer, inner).
var2 (numpy.ndarray) – Scan axes (outer, inner).
var1_unit (float) – Display scaling for each axis.
var2_unit (float) – Display scaling for each axis.
var1_label (str) – Axis labels.
var2_label (str) – Axis labels.
quantity (str) – Background colour-map quantity (see _background_data for the list).
plot_opts (PlotOptions, optional) – Display settings; defaults to PlotOptions().
name (optional) – Used for the title and the saved-file name.
flow (optional) – Used for the title and the saved-file name.
tau_boundary (optional) – Used for the title and the saved-file name.
albums.system
Module introducing the class SystemState bundles the synchrotron and rf parameters and is the entry point for fixed parameterset ALBuMS computations.
- class SystemState(ring: Synchrotron, cavity_list: list[CavityResonator])[source]
Bases:
objectThis class bundles the synchrotron and rf parameters and is the entry point for fixed parameterset ALBuMS computations.
- Use run to drive a Flow, composed of:
a chosen equilibrium solver (Bosch, Venturini or Alves).
paired with a chosen subset of instability theories (see albums.theories).
See albums.flow.DEFAULT_FLOWS for the prebuilt Bosch/Venturini/Alves flows, or build a custom Flow.
- Parameters
ring (Synchrotron object) – Ring parameters.
cavity_list (list of CavityResonator objects) – At least two cavities: the main cavity in position 0, followed by one or more harmonic cavities.
References
[1] : Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
[2] : Bosch, R. A., and C. S. Hsue. “Suppression of longitudinal coupled-bunch instabilities by a passive higher harmonic cavity.” Proceedings of International Conference on Particle Accelerators. IEEE, 1993.
[3] : Gamelin, A., Yamamoto, N. (2021). Equilibrium bunch density distribution with multiple active and passive RF cavities. IPAC’21 (MOPAB069).
[4] : Venturini, M. (2018). Passive higher-harmonic rf cavities with general settings and multibunch instabilities in electron storage rings. Physical Review Accelerators and Beams, 21(11), 114404.
[5] : Alves, Murilo B., and Fernando H. de Sá. “Equilibrium of longitudinal bunch distributions in electron storage rings with arbitrary impedance sources and generic filling patterns.” Physical Review Accelerators and Beams 26.9 (2023): 094402.
[6] : de Sá, F., & Alves, M. (2023). pycolleff and cppcolleff: modules for impedance analysis and wake-field induced instabilities evaluation. (Version 0.1.0) [Computer software]. https://doi.org/10.5281/zenodo.7974571
[7] : He, Tianlong. “Novel perturbation method for judging the stability of the equilibrium solution in the presence of passive harmonic cavities.” Physical Review Accelerators and Beams 25.9 (2022): 094402.
- _solve(solver: EquilibriumSolver, eq_opts: EquilibriumOptions) Equilibrium[source]
- run_equilibrium(flow: Flow, eq_opts: EquilibriumOptions) Result[source]
Solve only the beam equilibrium of a flow (no instability theories) and return a Result carrying bunch length, R-factor and xi.
- Parameters
flow (Flow) – The (equilibrium solver, theories) pipeline; only its equilibrium solver is used here.
eq_opts (EquilibriumOptions) – The beam current, integration boundary and every solver option.
- Returns
Structured result with theories={} (no instability theory evaluated).
- Return type
- run(flow: Flow, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0)) Result[source]
Run a Flow: solve the beam equilibrium with the flow’s equilibrium method, then evaluate each of its instability theories, returning a structured Result.
The flow selects the equilibrium solver and the subset of theories.
- Parameters
flow (Flow) – The (equilibrium solver, theories) pipeline. Use one of albums.DEFAULT_FLOWS or build a custom Flow.
eq_opts (EquilibriumOptions) – The beam current, integration boundary and every solver option.
theory_opts (TheoryOptions, optional) – The run-time inputs shared by the theories (HOM parameters, mode coupling). Defaults to TheoryOptions().
- Returns
Structured result, result.theories[name] holds each TheoryResult.
- Return type
albums.equilibrium
Stage 1 of the ALBuMS pipeline: beam-equilibrium solvers.
References
[1] : Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
[2] : Bosch, R. A., and C. S. Hsue. “Suppression of longitudinal coupled-bunch instabilities by a passive higher harmonic cavity.” Proceedings of International Conference on Particle Accelerators. IEEE, 1993.
[3] : Gamelin, A., Yamamoto, N. (2021). Equilibrium bunch density distribution with multiple active and passive RF cavities. IPAC’21 (MOPAB069).
[4] : Venturini, M. (2018). Passive higher-harmonic rf cavities with general settings and multibunch instabilities in electron storage rings. Physical Review Accelerators and Beams, 21(11), 114404.
[5] : Alves, Murilo B., and Fernando H. de Sá. “Equilibrium of longitudinal bunch distributions in electron storage rings with arbitrary impedance sources and generic filling patterns.” Physical Review Accelerators and Beams 26.9 (2023): 094402.
- class Capability(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Bases:
str,EnumWhat an equilibrium snapshot makes available to downstream theories.
- AMPLITUDE_FORM_FACTOR = 'amplitude_form_factor'
- TAYLOR_POTENTIAL = 'taylor_potential'
- PHASE_FORM_FACTOR = 'phase_form_factor'
- MBTRACK2_BLE = 'mbtrack2_ble'
- PYCOLLEFF_LE = 'pycolleff_le'
- FULL_DISTRIBUTION = 'full_distribution'
- ARBITRARY_FILLING = 'arbitrary_filling'
- BROADBAND_IMPEDANCE = 'broadband_impedance'
- TOUSCHEK_LIFETIME_RATIO = 'touschek_lifetime_ratio'
- static _generate_next_value_(name, start, count, last_values)
Generate the next value when not given.
name: the name of the member start: the initial start value or None count: the number of existing members last_values: the list of values assigned
- _new_member_(**kwargs)
Create and return a new object. See help(type) for accurate signature.
- _use_args_ = True
- _member_names_ = ['AMPLITUDE_FORM_FACTOR', 'TAYLOR_POTENTIAL', 'PHASE_FORM_FACTOR', 'MBTRACK2_BLE', 'PYCOLLEFF_LE', 'FULL_DISTRIBUTION', 'ARBITRARY_FILLING', 'BROADBAND_IMPEDANCE', 'TOUSCHEK_LIFETIME_RATIO']
- _member_map_ = {'AMPLITUDE_FORM_FACTOR': Capability.AMPLITUDE_FORM_FACTOR, 'ARBITRARY_FILLING': Capability.ARBITRARY_FILLING, 'BROADBAND_IMPEDANCE': Capability.BROADBAND_IMPEDANCE, 'FULL_DISTRIBUTION': Capability.FULL_DISTRIBUTION, 'MBTRACK2_BLE': Capability.MBTRACK2_BLE, 'PHASE_FORM_FACTOR': Capability.PHASE_FORM_FACTOR, 'PYCOLLEFF_LE': Capability.PYCOLLEFF_LE, 'TAYLOR_POTENTIAL': Capability.TAYLOR_POTENTIAL, 'TOUSCHEK_LIFETIME_RATIO': Capability.TOUSCHEK_LIFETIME_RATIO}
- _value2member_map_ = {'amplitude_form_factor': Capability.AMPLITUDE_FORM_FACTOR, 'arbitrary_filling': Capability.ARBITRARY_FILLING, 'broadband_impedance': Capability.BROADBAND_IMPEDANCE, 'full_distribution': Capability.FULL_DISTRIBUTION, 'mbtrack2_ble': Capability.MBTRACK2_BLE, 'phase_form_factor': Capability.PHASE_FORM_FACTOR, 'pycolleff_le': Capability.PYCOLLEFF_LE, 'taylor_potential': Capability.TAYLOR_POTENTIAL, 'touschek_lifetime_ratio': Capability.TOUSCHEK_LIFETIME_RATIO}
- _unhashable_values_ = []
- _member_type_
alias of
str
- _value_repr_()
Return repr(self).
- class Equilibrium(converged: bool, I0: float | None = None, bunch_length: float | None = None, a: float | None = None, b: float | None = None, c: float | None = None, F: np.ndarray | None = None, PHI: np.ndarray | None = None, backend_BLE: BeamLoadingEquilibrium | None = None, backend_LE: LongitudinalEquilibrium | None = None, cavity_list: list[CavityResonator] | None = None, Touschek: float = nan, xi: float | None = None, capabilities: frozenset[Capability] = <factory>)[source]
Bases:
objectImmutable result of a Stage-1 solve, passed to every Stage-2 theory.
Fields are None when the producing solver does not provide them; a theory must never read a field outside the solver’s capabilities (the Flow validation guarantees it never has to).
- converged: bool
- I0: float | None = None
- bunch_length: float | None = None
- a: float | None = None
- b: float | None = None
- c: float | None = None
- F: np.ndarray | None = None
- PHI: np.ndarray | None = None
- backend_BLE: BeamLoadingEquilibrium | None = None
- backend_LE: LongitudinalEquilibrium | None = None
- cavity_list: list[CavityResonator] | None = None
- Touschek: float = nan
- xi: float | None = None
- capabilities: frozenset[Capability]
- has(*caps: Capability) bool[source]
- __init__(converged: bool, I0: float | None = None, bunch_length: float | None = None, a: float | None = None, b: float | None = None, c: float | None = None, F: np.ndarray | None = None, PHI: np.ndarray | None = None, backend_BLE: BeamLoadingEquilibrium | None = None, backend_LE: LongitudinalEquilibrium | None = None, cavity_list: list[CavityResonator] | None = None, Touschek: float = nan, xi: float | None = None, capabilities: frozenset[Capability] = <factory>) None
- class EquilibriumSolver(*args, **kwargs)[source]
Bases:
ProtocolStage-1 strategy interface.
solve receives the ring, the cavity list (mutated in place) and an EquilibriumOptions bundle (carrying the beam current, the integration boundary and every solver option), and returns an Equilibrium stamped with provides.
- name: str
- provides: frozenset[albums.equilibrium.Capability]
- solve(ring: Synchrotron, cavity_list: list[CavityResonator], opts: EquilibriumOptions) Equilibrium[source]
- __init__(*args, **kwargs)
- _abc_impl = <_abc._abc_data object>
- _is_protocol = True
- _is_runtime_protocol = True
- resolve_tau_boundary(ring: Synchrotron, tau_boundary: float | None) float[source]
Integration half-window: the given value, or 0.1 times the RF period.
- _compute_xi(cavity_list: list[CavityResonator]) float[source]
First-harmonic/main ‘force’ ratio (Bosch near Eq. 7).
Defined for any list of two or more cavities (element 0 is the main cavity); uses the first harmonic cavity. A per-harmonic-cavity xi is left for the full multi-harmonic-cavity physics.
- _passive_bosch(ring: Synchrotron, cavity_list: list[CavityResonator], tau_boundary: float, opts: EquilibriumOptions) tuple[source]
- _active_bosch(ring: Synchrotron, cavity_list: list[CavityResonator], tau_boundary: float, opts: EquilibriumOptions) tuple[source]
- _venturini(ring: Synchrotron, cavity_list: list[CavityResonator], tau_boundary: float, opts: EquilibriumOptions) tuple[source]
- _alves(ring: Synchrotron, cavity_list: list[CavityResonator], tau_boundary: float, opts: EquilibriumOptions) tuple[source]
- class _SolverRepr[source]
Bases:
objectMixin giving the stateless solver classes a clean ClassName() repr.
- class BoschEquilibrium[source]
Bases:
_SolverReprOriginal Bosch [1] iteration. Amplitude form factor + bunch length only.
- name = 'Bosch'
- provides = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL})
- solve(ring: Synchrotron, cavity_list: list[CavityResonator], opts: EquilibriumOptions) Equilibrium[source]
- class VenturiniEquilibrium[source]
Bases:
_SolverReprVenturini [3,4] via mbtrack2 BeamLoadingEquilibrium. Passive and active HC.
- name = 'Venturini'
- provides = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.MBTRACK2_BLE, Capability.PHASE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL, Capability.TOUSCHEK_LIFETIME_RATIO})
- solve(ring: Synchrotron, cavity_list: list[CavityResonator], opts: EquilibriumOptions) Equilibrium[source]
- class AlvesEquilibrium[source]
Bases:
_SolverReprAlves [5] via pycolleff LongitudinalEquilibrium. Passive HC only.
- name = 'Alves'
- provides = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.ARBITRARY_FILLING, Capability.BROADBAND_IMPEDANCE, Capability.FULL_DISTRIBUTION, Capability.PHASE_FORM_FACTOR, Capability.PYCOLLEFF_LE, Capability.TAYLOR_POTENTIAL, Capability.TOUSCHEK_LIFETIME_RATIO})
- solve(ring: Synchrotron, cavity_list: list[CavityResonator], opts: EquilibriumOptions) Equilibrium[source]
albums.theories
Stage 2 of the ALBuMS pipeline: instability theories.
Each theory takes the SystemState and the Stage-1 Equilibrium, and returns a TheoryResult. The actual physics lives in albums.physics so theories.py does only the orchestration.
- class Category(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Bases:
str,EnumPhysical category a theory belongs to.
The flow-agnostic accessors (Result / ResultArray) resolve “the Robinson result” / “the PTBL result” by category, so several concrete theories can share one category. Values are independent of each theory’s name.
- ZERO_FREQUENCY = 'zero_frequency'
- ROBINSON = 'robinson'
- HOM = 'hom'
- PTBL = 'ptbl'
- static _generate_next_value_(name, start, count, last_values)
Generate the next value when not given.
name: the name of the member start: the initial start value or None count: the number of existing members last_values: the list of values assigned
- _new_member_(**kwargs)
Create and return a new object. See help(type) for accurate signature.
- _use_args_ = True
- _member_names_ = ['ZERO_FREQUENCY', 'ROBINSON', 'HOM', 'PTBL']
- _member_map_ = {'HOM': Category.HOM, 'PTBL': Category.PTBL, 'ROBINSON': Category.ROBINSON, 'ZERO_FREQUENCY': Category.ZERO_FREQUENCY}
- _value2member_map_ = {'hom': Category.HOM, 'ptbl': Category.PTBL, 'robinson': Category.ROBINSON, 'zero_frequency': Category.ZERO_FREQUENCY}
- _unhashable_values_ = []
- _member_type_
alias of
str
- _value_repr_()
Return repr(self).
- class TheoryResult(name: str, unstable: bool | numpy.ndarray, growth_rate: float | numpy.ndarray = 0.0, mode_frequency: numpy.ndarray | None = None, converged: bool | numpy.ndarray = True, extra: dict = <factory>)[source]
Bases:
objectOutcome of one instability theory at one operating point.
- name: str
- unstable: bool | numpy.ndarray
- growth_rate: float | numpy.ndarray = 0.0
- mode_frequency: numpy.ndarray | None = None
- converged: bool | numpy.ndarray = True
- extra: dict
- __init__(name: str, unstable: bool | numpy.ndarray, growth_rate: float | numpy.ndarray = 0.0, mode_frequency: numpy.ndarray | None = None, converged: bool | numpy.ndarray = True, extra: dict = <factory>) None
- class InstabilityTheory(*args, **kwargs)[source]
Bases:
ProtocolStage-2 strategy interface.
The evaluate methods receives the SystemState, the Stage-1 Equilibrium and a TheoryOptions bundle, and returns a TheoryResult.
- name: str
- requires: frozenset[albums.equilibrium.Capability]
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- __init__(*args, **kwargs)
- _abc_impl = <_abc._abc_data object>
- _is_protocol = True
- _is_runtime_protocol = True
- class _TheoryRepr[source]
Bases:
objectMixin giving the theory classes a clean repr from their instance config.
- class ZeroFrequency[source]
Bases:
_TheoryReprZero-frequency (DC Robinson) instability.
Physics: albums.physics.zero_frequency.zero_frequency_instability.
- name = 'zero_frequency'
- category = 'zero_frequency'
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class RobinsonCoupling[source]
Bases:
_TheoryReprRobinson dipole/quadrupole modes with mode coupling.
Physics: albums.physics.robinson.robinson_coupling.
- name = 'robinson_coupling'
- category = 'robinson'
- coupled = True
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class RobinsonNoCoupling[source]
Bases:
_TheoryReprRobinson dipole to octupole modes without mode coupling.
Physics: albums.physics.robinson.robinson_no_coupling.
- name = 'robinson_no_coupling'
- category = 'robinson'
- coupled = False
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class HOMCoupledBunch[source]
Bases:
_TheoryReprHOM-driven dipole coupled-bunch instability.
Reads the f_HOM / Z_HOM fields of TheoryOptions at evaluation time. Physics: albums.physics.coupled_bunch.dipole_coupled_bunch.
- name = 'hom_coupled_bunch'
- category = 'hom'
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class BoschMode1[source]
Bases:
_TheoryReprBosch coupled-bunch mode l=1 with Landau threshold.
Physics: albums.physics.ptbl.coupled_bunch_mode1.
- name = 'bosch_mode1'
- category = 'ptbl'
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.TAYLOR_POTENTIAL})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class PTBLHe[source]
Bases:
_TheoryReprPeriodic transient beam loading (PTBL) instability via He’s perturbation criterion.
Physics: albums.physics.ptbl.ptbl_he.
- name = 'ptbl_he'
- category = 'ptbl'
- requires = frozenset({Capability.AMPLITUDE_FORM_FACTOR, Capability.PHASE_FORM_FACTOR})
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class PTBLAlves(max_azi: int = 10, max_rad: int = 10)[source]
Bases:
_TheoryReprPeriodic transient beam loading (PTBL) instability via Alves mode analysis.
Needs the pycolleff LE + full distribution, so Alves only. Physics: albums.physics.ptbl.ptbl_alves.
- name = 'ptbl_alves'
- category = 'ptbl'
- requires = frozenset({Capability.FULL_DISTRIBUTION, Capability.PYCOLLEFF_LE})
- __init__(max_azi: int = 10, max_rad: int = 10)[source]
max_azi, max_rad : truncation of the azimuthal / radial mode expansion.
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
- class RobinsonGLMCI(max_azi: int = 2, max_rad: int = 0)[source]
Bases:
_TheoryReprRobinson instabilities via the Gaussian longitudinal mode-coupling instability (GLMCI) method. Alves only.
Physics: albums.physics.robinson.robinson_glmci.
- name = 'robinson_glmci'
- category = 'robinson'
- coupled = True
- requires = frozenset({Capability.FULL_DISTRIBUTION, Capability.PYCOLLEFF_LE})
- __init__(max_azi: int = 2, max_rad: int = 0)[source]
max_azi, max_rad : truncation of the azimuthal / radial mode expansion.
- evaluate(state: SystemState, eq: Equilibrium, opts: TheoryOptions) TheoryResult[source]
albums.flow
Stage 3 of the ALBuMS pipeline: flows, the aggregated result, and the computed compatibility matrix.
- exception IncompatibleFlowError[source]
Bases:
ValueErrorRaised by Flow.validate when a theory needs a capability the solver does not provide.
- class Result(converged: bool, equilibrium: ~albums.equilibrium.Equilibrium, theories: dict[str, albums.theories.TheoryResult] = <factory>, Touschek: float = nan, xi: float | None = None)[source]
Bases:
objectAggregated outcome of running a flow at one operating point.
- converged: bool
- equilibrium: Equilibrium
- theories: dict[str, albums.theories.TheoryResult]
- Touschek: float = nan
- xi: float | None = None
- get(*names: str) albums.theories.TheoryResult | None[source]
Return the first present TheoryResult among names, else None.
- property any_unstable: bool
- property zero_frequency: bool
- property robinson_flags: ndarray
- property hom: bool
- property ptbl: bool
- property growth_robinson: ndarray
- property growth_zero_frequency: float
- property growth_PTBL: float | numpy.ndarray
- __init__(converged: bool, equilibrium: ~albums.equilibrium.Equilibrium, theories: dict[str, albums.theories.TheoryResult] = <factory>, Touschek: float = nan, xi: float | None = None) None
- class Flow(equilibrium: EquilibriumSolver, theories: list[albums.theories.InstabilityTheory], name: str | None = None)[source]
Bases:
objectA user-chosen pipeline: one equilibrium solver + a subset of theories.
- equilibrium: EquilibriumSolver
- theories: list[albums.theories.InstabilityTheory]
- name: str | None = None
- required_capabilities() frozenset[albums.equilibrium.Capability][source]
- validate() None[source]
Raise IncompatibleFlowError if any theory is incompatible with the chosen equilibrium solver. Call this before any compute.
- __init__(equilibrium: EquilibriumSolver, theories: list[albums.theories.InstabilityTheory], name: str | None = None) None
- flow_label(flow) str[source]
Short label for filenames: the flow name (or ‘custom’), or the name string.
- is_compatible(solver: EquilibriumSolver, theory: InstabilityTheory) bool[source]
- compatibility_matrix(solvers: Optional[Iterable[EquilibriumSolver]] = None, theories: Optional[Iterable[InstabilityTheory]] = None) str[source]
Render the solver x theory compatibility table as a Markdown string.
Generated from the capability sets so the docs cannot drift from the code.
albums.saveload
HDF5 save/load helpers for scan outputs.
The scan output is a nested dict of numpy arrays mirroring Result (produced by results_to_arrays), optionally with a scan_meta group carrying the swept axes/labels/flow; it is written to nested HDF5 groups and read back into a ResultArray. The on-disk schema is therefore generated from the dataclasses — there is no hand-maintained key list. Optimisation scans now use this same format (the optimised psi map lives in scan_meta/extra).
- _write_group(grp, data: dict) None[source]
Recursively write a (possibly nested) dict of arrays into an HDF5 group.
- _read_group(grp) dict[source]
Recursively read an HDF5 group into a (possibly nested) dict of arrays.
- save_hdf5(filename: str, data_dict: dict) None[source]
Write a (possibly nested) dict of arrays to filename (mode “w”).
albums.scan
Module where parameter scans and optimization scans are defined.
Every scan takes a SystemState (the ring + cavity list bundle) together with a resolved set of typed option objects (EquilibriumOptions, TheoryOptions, and for the optimisation scans OptimiserOptions), plus a ScanOptions controlling the sweep itself. These are bundled with the resolved flow into a ScanContext. The cavity list is deep-copied out of the state, so the caller’s SystemState is left untouched as grid points mutate cavity attributes.
- _local_rows(var1)[source]
This rank’s slice of var1 plus the matching global row indices.
Splitting is even-as-possible (np.array_split), so a rank may own 0+ rows; the global indices let after-opti passes address the full gathered psi map.
- class ScanContext(cavity_list: list[CavityResonator], ring: Synchrotron, flow: object, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = <factory>, opti_opts: OptimiserOptions = <factory>, scan_opts: ScanOptions = <factory>, psi0_HC: float | None = None, bounds: tuple | None = None, RoQ: float | None = None)[source]
Bases:
objectEverything a scan grid point needs, bundled once per scan.
- Variables
cavity_list (list of CavityResonator) – Main cavity in position 0, the harmonic cavity in position 1.
ring (Synchrotron) – Ring configuration.
flow (Flow) – The already-resolved solve flow.
eq_opts (EquilibriumOptions) – Beam current, integration boundary and solver options.
theory_opts (TheoryOptions) – Shared theory inputs.
opti_opts (OptimiserOptions) – Optimisation settings (used by the optimisation scans only).
scan_opts (ScanOptions) – Sweep settings (skip).
bounds (psi0_HC,) – Initial guess and bounds for the optimisation scans.
RoQ (float or None) – Fixed R/Q value used by scan_psi_HC_Q0.
- cavity_list: list[CavityResonator]
- ring: Synchrotron
- flow: object
- eq_opts: EquilibriumOptions
- theory_opts: TheoryOptions
- opti_opts: OptimiserOptions
- scan_opts: ScanOptions
- psi0_HC: float | None = None
- bounds: tuple | None = None
- RoQ: float | None = None
- __init__(cavity_list: list[CavityResonator], ring: Synchrotron, flow: object, eq_opts: EquilibriumOptions, theory_opts: TheoryOptions = <factory>, opti_opts: OptimiserOptions = <factory>, scan_opts: ScanOptions = <factory>, psi0_HC: float | None = None, bounds: tuple | None = None, RoQ: float | None = None) None
- _make_ctx(state, flow, eq_opts, theory_opts, opti_opts=None, scan_opts=None, **extra) ScanContext[source]
Build a ScanContext, resolving the flow once with the chosen mode coupling.
The cavity list is deep-copied out of state so that mutating cavity attributes per grid point never touches the caller’s SystemState.
- _strip_unpicklable(res)[source]
Drop the live backend handles / cavity objects from a Result before MPI pickling. results_to_arrays ignores these fields anyway, and the pycolleff backend_LE carries an unpicklable closure (see physics.ptbl.prepare_alves_le).
- _run_grid(func, var1, var2, ctx)[source]
Evaluate func(v1, v2, ctx) over the var1 x var2 grid, returning a 2D object array of Result on rank 0 (None on other ranks).
var1 rows are split across MPI ranks and object-gathered (pickling) to the root — the entries are Result objects (nested arrays + dataclasses), so the buffer-based comm.Gather cannot be used. Grid points skipped by the skip fast-path stay None and are filled with sentinels downstream.
- _result(ctx, grid, var1, var2, u1, u2, l1, l2, extra=None)[source]
Rank-0: wrap the gathered grid into a self-describing ResultArray (axes, units, labels, flow). Returns None on other ranks.
- __scan_opti(func, var1, var2, ctx)[source]
Optimisation grid: gather the full Result per point to root, and the optimised psi to every rank (needed by the after-opti pass).
- scan_psi_I0(state, psi_HC_vals, currents, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_RoQ(state, psi_HC_vals, RoQ_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- _opti_result(ctx, grid, psi, var1, var2, u1, u2, l1, l2)[source]
Build the optimisation ResultArray with the optimised psi grid in extra.
- scan_RoQ_I0(state, current_vals, RoQ_vals, flow, eq_opts, psi0_HC, bounds, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts=OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), scan_opts=ScanOptions(skip=False), scan_after_opti=True, psi_add_after_opti=-0.1)[source]
Optimise psi_HC over a current x R/Q grid.
Returns the optimisation ResultArray (background quantities xi/Touschek/ bunch_length/psi + flow instability markers). When scan_after_opti is True, a second scan re-run slightly off the optimum is attached as result.after_opti.
- scan_RoQ_I0_equilibrium(state, current_vals, RoQ_vals, flow, eq_opts, psi0_HC, bounds, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts=OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), scan_opts=ScanOptions(skip=False))[source]
- scan_RoQ_Q0(state, Q0_vals, RoQ_vals, flow, eq_opts, psi0_HC, bounds, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts=OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), scan_opts=ScanOptions(skip=False), scan_after_opti=True, psi_add_after_opti=-0.1)[source]
- scan_RoQ_Q0_equilibrium(state, Q0_vals, RoQ_vals, flow, eq_opts, psi0_HC, bounds, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), opti_opts=OptimiserOptions(method_opti='COBYLA', tol_opti=0.01, maxiter_opti=1000, rhobeg_opti=0.1, method='Nelder-Mead', tol=0.05, loop_option=False, add_psi_loop=0.02, max_loop=200, auto_psi_input=False, xi_init_input=0.8, debug=False), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_QL(state, psi_HC_vals, QL_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_MCdet(state, psi_HC_vals, MCdet_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_MC_Rs(state, psi_HC_vals, MC_Rs_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_MC_beta(state, psi_HC_vals, MC_beta_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_psi_HC_Q0(state, psi_HC_vals, HC_Q0_vals, RoQ, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_MC_Vc_HC_Vc_active(state, MC_Vc_vals, HC_Vc_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_MC_Vc_MC_psi_active(state, MC_Vc_vals, MC_psi_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
- scan_MC_psi_HC_psi_active(state, MC_psi_vals, HC_psi_vals, flow, eq_opts, theory_opts=TheoryOptions(mode_coupling=True, f_HOM=0, Z_HOM=0), scan_opts=ScanOptions(skip=False))[source]
albums.result_io
Turn a grid of Result objects into a nested dict of numpy arrays whose structure mirrors Result itself — the single source of truth for the scan / HDF5 schema (it is generated from the dataclass definitions, never hand-maintained).
The output layout, for a scan over var1 × var2 grid points:
converged (V1, V2) bool
Touschek (V1, V2) float
xi (V1, V2) float
equilibrium/<field> (V1, V2[, k]) float / bool
theories/<name>/<field> (V1, V2[, n]) float / bool
Only numeric / boolean (and numeric ndarray) fields are persisted; live backend handles (Equilibrium.backend_BLE / backend_LE), the cavity_list and the capabilities set are non-serialisable and skipped automatically by the type filter. Missing points (failed/None results, or a theory absent from a given flow) are filled with a sentinel: NaN for floats, False for booleans.
- _collect(grid_shape: tuple, getter: Callable, *, skip_if_all_none: bool = False)[source]
Build one numpy array over the grid from getter applied per point.
getter returns the field value for a grid point (or None if the result is missing / the field is unset). The trailing shape and dtype are inferred from the first non-None, numeric sample; non-numeric samples are skipped (returns None). Missing points get a NaN (float) / False (bool) sentinel.
- results_to_arrays(results: ndarray) dict[source]
Convert an object array of Result into a nested dict.
- Parameters
results (numpy.ndarray) – Object array (any leading shape — typically 1D or 2D) whose entries are Result instances, or None for grid points that were skipped.
- Returns
Nested {field: array | {subfield: array}} mirroring Result (see the module docstring for the layout).
- Return type
dict
- class ResultArray(data: dict, *, var1=None, var2=None, var1_unit: float = 1.0, var2_unit: float = 1.0, var1_label: str | None = None, var2_label: str | None = None, name: str | None = None, flow=None, tau_boundary=None, extra: dict | None = None)[source]
Bases:
objectA grid of scan results, stored as the nested dict of arrays produced by results_to_arrays.
Wraps that dict with vectorized, flow-agnostic accessors (the grid-level analogue of Result’s category accessors), ND indexing, HDF5 save/load and a plotting shortcut. Missing categories or grid points read back as sentinels (False for flags, NaN for floats).
A scan additionally attaches scan metadata — the swept axes, their display units/labels, the flow and a name — so the object is self-describing: result.plot(“xi”) and result.save() need no further arguments. A bare ResultArray(data) (built by results_to_arrays or loaded from a plain HDF5 file) leaves these as None/identity and still works. The extra dict holds optimisation-only maps (e.g. the optimised psi grid) that are not part of the Result schema but are plottable as a background quantity.
- Parameters
data (dict) – Nested dict from results_to_arrays (or loaded from HDF5).
var1 (numpy.ndarray, optional) – The swept axes (outer, inner). None for a bare result.
var2 (numpy.ndarray, optional) – The swept axes (outer, inner). None for a bare result.
var1_unit (float) – Multiplicative display scaling for each axis.
var2_unit (float) – Multiplicative display scaling for each axis.
var1_label (str, optional) – Axis labels for plots.
var2_label (str, optional) – Axis labels for plots.
name (str) – Base name used for plot titles and saved files.
flow (Flow or str, optional) – The flow that produced the scan (used for the saved-file label only; marker derivation reads the theory names already stored in data).
tau_boundary (float, optional) – Resolved integration half-window, used only in the Bosch plot filename.
extra (dict, optional) – Named 2D arrays outside the Result schema (e.g. {“psi”: grid}).
- __init__(data: dict, *, var1=None, var2=None, var1_unit: float = 1.0, var2_unit: float = 1.0, var1_label: str | None = None, var2_label: str | None = None, name: str | None = None, flow=None, tau_boundary=None, extra: dict | None = None)[source]
- property shape: tuple
Grid shape (var1, var2).
- property converged
- property Touschek
- property xi
- property bunch_length
RMS bunch length per grid point, in [s].
- property theories: dict
- property zero_frequency
- property robinson_flags
- property modes
- property converged_modes
- property hom
- property ptbl
- property growth_robinson
- property growth_zero_frequency
- property growth_ptbl
- _collapse_trailing(arr: ndarray, reduce: Callable) ndarray[source]
Reduce an array of shape self.shape followed by trailing dimensions down to self.shape, where the trailing dimension(s) are whatever per-mode axes the field carries (possibly none). Grid-dimension-agnostic: works for 1D and 2D scans alike.
- property any_unstable: ndarray
True where at least one theory in this result flags instability at that point. Grid-level analogue of Result.any_unstable.
Points where a theory didn’t run (e.g. because the equilibrium itself failed there) read as not-unstable.
- property theory_converged: ndarray
True where every theory that tracks its own convergence (TheoryResult.converged) succeeded. Theories that don’t track convergence default to True and have no effect, so a new theory with a ‘converged’ field is picked up automatically.
- static _meta_kwargs(meta: dict) dict[source]
Turn a loaded scan-metadata group back into __init__ keyword args.
- classmethod load(file: str) ResultArray[source]
Load a ResultArray (with any scan metadata) from a nested-HDF5 file.
- plot(quantity, var1=None, var2=None, var1_unit=None, var2_unit=None, var1_label=None, var2_label=None, plot_opts=None, name=None, flow=None, tau_boundary=None)[source]
Plot one background quantity plus the flow’s instability markers.
Axes metadata (var1/var2, units, labels, name, flow, tau_boundary) fall back to the values stored on the result, so a scan output plots with just result.plot(“xi”). A bare ResultArray must supply var1 and var2.
Physics kernel
albums.physics.potential
Equilibrium-derived closed-form quantities: RF potential well, bunch length, form factors, incoherent (Robinson) frequency and the Landau-damping threshold.
These are the low-level quantities shared by the Stage-1 solvers (albums.equilibrium) and by nearly every Stage-2 theory.
References
- [1] Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities
with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
- potential_decomposition(ring: Synchrotron, cavity_list: list[CavityResonator]) tuple[float, float, float][source]
Taylor coefficients of the RF potential well about the synchronous point.
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
- Returns
a, b, c – Quadratic, cubic and quartic potential-well coefficients.
- Return type
float
References
Eq. (4)-(6) in [1].
- bunch_length(ring: Synchrotron, a: float, b: float, c: float, tau_boundary: float) float[source]
RMS bunch length from the potential-well distribution.
Integrates the Boltzmann distribution of the quartic potential well over [-tau_boundary, tau_boundary] and returns its standard deviation.
- Parameters
ring (Synchrotron) – Ring parameters.
a (float) – Potential-well coefficients from potential_decomposition.
b (float) – Potential-well coefficients from potential_decomposition.
c (float) – Potential-well coefficients from potential_decomposition.
tau_boundary (float) – Integration half-width in [s].
- Returns
RMS bunch length in [s].
- Return type
float
References
Eq. (8) in [1].
- form_factors(f: float, m: int, bunch_length: float) float[source]
Gaussian-bunch amplitude form factor at harmonic m of frequency f.
- Parameters
f (float) – Fundamental frequency in [Hz].
m (int) – Harmonic number of the cavity.
bunch_length (float) – RMS bunch length in [s].
- Returns
Form factor exp(-(m omega sigma)^2 / 2) in [0, 1].
- Return type
float
- robinson_frequency(ring: Synchrotron, cavity_list: list[CavityResonator], F: np.ndarray) float[source]
Incoherent synchrotron (Robinson) angular frequency omega_r.
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
F (numpy.ndarray) – Amplitude form factor per cavity.
- Returns
Synchrotron angular frequency in [rad/s].
- Return type
float
References
Eq. (10) in [1].
- landau_threshold(ring: Synchrotron, omega_r: float, c: float, b: float) np.ndarray[source]
Landau-damping frequency-spread threshold for modes mu = 1..4.
- Parameters
ring (Synchrotron) – Ring parameters.
omega_r (float) – Synchrotron angular frequency from robinson_frequency.
c (float) – Quartic and cubic potential-well coefficients from potential_decomposition.
b (float) – Quartic and cubic potential-well coefficients from potential_decomposition.
- Returns
Shape (4, 1) thresholds for the dipole, quadrupole, sextupole and octupole modes.
- Return type
numpy.ndarray
References
Eq. (19) in [1].
albums.physics.robinson
Robinson (coupled-bunch mode 0) instabilities: - Coupled/uncoupled Robinson dipole to octupole modes, including fast mode-coupling, based on Bosch equations [1]. - Robinson instabilites using the Gaussian longitudinal mode-coupling instability method [2].
References
- [1] Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities
with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
- [2] Alves, Murilo B. “Theoretical models for longitudinal coupled-bunch instabilities
driven by harmonic cavities in electron storage rings.” Physical Review Accelerators and Beams 28.3 (2025): 034401.
- omega_n(ring: Synchrotron, cavity: CavityResonator) float[source]
Detuned resonant angular frequency of a cavity. Near Eq. (B.3) in [1].
- phi_pm(ring: Synchrotron, cavity: CavityResonator, Omega: float, sign: str) float[source]
Upper (“+”) / lower (“-”) sideband phase. Near Eq. (B.4) in [1].
- A_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float) float[source]
Cavity transfer term à (dipole). Bosch Appendix B [1].
- B_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, bunch_length: float) float[source]
Cavity transfer term B̃ (quadrupole). Bosch Appendix B [1].
- D_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, bunch_length: float) float[source]
Cavity transfer cross-term D̃. Bosch Appendix B [1].
- a_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float) float[source]
Cavity transfer term ã (dipole damping). Bosch Appendix B [1].
- b_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, bunch_length: float) float[source]
Cavity transfer term b̃ (quadrupole damping). Bosch Appendix B [1].
- d_tilde(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, bunch_length: float) float[source]
Cavity transfer cross-term d̃. Bosch Appendix B [1].
- ar_B11(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, bunch_length: float, omega_r: float) float[source]
Coupled-mode damping rate. Eq. (B.11) in [1].
- Omega_B13(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, alpha_r: float, bunch_length: float, omega_r: float, sign: str, abs_val: bool = True, return_root: bool = False) float[source]
Coupled-mode frequency (or its discriminant). Eq. (B.13) in [1].
- robinson_damping_rate(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, mu: int, bunch_length: float) float[source]
Radiation-free Robinson damping rate of mode mu. Eq. (16) in [1].
- robinson_no_coupling(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, omega_r: float, bunch_length: float, landau_threshold: np.ndarray) tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray][source]
Robinson modes mu = 1..4 solved independently (no mode coupling).
For each mode the coherent frequency is found from the dispersion relation, then flagged unstable if its (radiation-included) damping rate is negative and its complex frequency shift exceeds the Landau threshold.
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
I0 (float) – Beam current in A.
F (numpy.ndarray) – Amplitude form factor per cavity.
omega_r (float) – Synchrotron angular frequency.
bunch_length (float) – RMS bunch length in [s].
landau_threshold (numpy.ndarray) – Per-mode thresholds from landau_threshold.
- Returns
robinson (numpy.ndarray of bool, shape (4,)) – Instability flag per mode.
Omega (numpy.ndarray, shape (4,)) – Coherent angular frequency per mode.
converged (numpy.ndarray of bool, shape (4,)) – Root-finder convergence per mode.
growth (numpy.ndarray, shape (4,)) – Net growth rate (radiation included) per mode.
References
Eq. (15)-(16) in [1].
- robinson_coupling(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, omega_r: float, bunch_length: float, landau_threshold: np.ndarray, abs_val: bool = True) tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray][source]
Coupled Robinson dipole/quadrupole modes with fast mode-coupling.
Solves the coupled dipole and quadrupole dispersion relations (Eq. B.11/B.13), flags each as Landau-stabilised or not, and detects fast mode-coupling when the discriminant goes negative.
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
I0 (float) – Beam current in A.
F (numpy.ndarray) – Amplitude form factor per cavity.
omega_r (float) – Synchrotron angular frequency.
bunch_length (float) – RMS bunch length in [s].
landau_threshold (numpy.ndarray) – Per-mode thresholds from landau_threshold.
abs_val (bool, optional) – Take the absolute value of the discriminant when solving (default True).
- Returns
robinson (numpy.ndarray of bool, shape (4,)) – [coupled_dipole, coupled_quadrupole, fast_coupling_by_dipole, fast_coupling_by_quadrupole].
Omega (numpy.ndarray, shape (2,)) – Coherent dipole and quadrupole angular frequencies.
converged (numpy.ndarray of bool, shape (2,)) – Root-finder convergence for dipole and quadrupole.
growth (numpy.ndarray, shape (4,)) – Net growth rate per entry of robinson.
References
Appendix B, Eq. (B.11)-(B.13) in [1].
- robinson_glmci(ring: Synchrotron, LE: LongitudinalEquilibrium, max_azi: int = 2, max_rad: int = 0) tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray][source]
Robinson (coupled-bunch mode 0) instabilites using the Gaussian longitudinal mode-coupling instability method [2].
This method does not distinguish between dipole Robinson, quadrupole Robisonson or fast-mode coupling instability. A positive result is flagged as fast-mode coupling instabilty.
- Parameters
ring (Synchrotron) – Ring parameters.
LE (LongitudinalEquilibrium) – Solved pycolleff equilibrium handle.
max_azi (int, optional) – Maximum azimuthal mode number (default 2).
max_rad (int, optional) – Maximum radial mode number (default 0).
- Returns
robinson (numpy.ndarray of bool, shape (4,)) – [False, False, FMCI, FMCI] (the fast-coupling dipole/quadrupole slots).
Omega (numpy.ndarray, shape (2,)) – Real parts of the first two eigenfrequencies.
converged (numpy.ndarray of bool, shape (2,)) – Always [True, True] (the eigensolver does not iterate).
growth (numpy.ndarray, shape (4,)) – Net growth rate placed in the fast-coupling slots.
References
Alves [2].
albums.physics.zero_frequency
Zero-frequency (DC Robinson) instability: the per-mode mu = 1..4 stability bound without mode coupling, and the coupled criterion built from the Robinson terms [1].
References
- [1] Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities
with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
- zero_frequency_no_coupling(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, mu: int, bunch_length: float) float[source]
Per-mode zero-frequency stability bound (no coupling). Eq. (14) in [1].
- zero_frequency_instability(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, omega_r: float, bunch_length: float, mode_coupling: bool) bool[source]
Zero-frequency (DC Robinson) instability test.
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
I0 (float) – Beam current in A.
F (numpy.ndarray) – Amplitude form factor per cavity.
omega_r (float) – Synchrotron angular frequency from robinson_frequency.
bunch_length (float) – RMS bunch length in [s].
mode_coupling (bool) – If True use the coupled criterion (Eq. B.12); otherwise the per-mode mu = 1..4 criterion (Eq. 14).
- Returns
True if the equilibrium is zero-frequency unstable.
- Return type
bool
References
Eq. (14) / (B.12) in [1].
albums.physics.coupled_bunch
HOM-driven longitudinal dipole coupled-bunch instability: - Growth-rate estimate using Bosch [1] resonant approximation, compared against approxmiate the Landau-damping threshold from rf potential decomposition.
References
- [1] Bosch, R. A., K. J. Kleman, and J. J. Bisognano. “Robinson instabilities
with a higher-harmonic cavity.” Physical Review Special Topics-Accelerators and Beams 4.7 (2001): 074401.
- dipole_coupled_bunch_growth_rate(ring: Synchrotron, I0: float, f_HOM: float, Z_HOM: float, bunch_length: float, omega_r: float) float[source]
Resonant dipole coupled-bunch growth rate. Eq. (22) in [1].
- dipole_coupled_bunch(ring: Synchrotron, I0: float, f_HOM: float | np.ndarray, Z_HOM: float | np.ndarray, bunch_length: float, omega_r: float, landau: np.ndarray) bool[source]
HOM-driven dipole coupled-bunch instability test.
Uses the resonant dipole_coupled_bunch_growth_rate for each HOM in the supplied list. The instability is flagged only if the HOM growth rate exceeds both radiation damping and the dipole Landau threshold.
- Parameters
ring (Synchrotron) – Ring parameters.
I0 (float) – Beam current in A.
f_HOM (float or array-like) – HOM resonant frequency in [Hz] and shunt impedance in [Ohm].
Z_HOM (float or array-like) – HOM resonant frequency in [Hz] and shunt impedance in [Ohm].
bunch_length (float) – RMS bunch length in [s].
omega_r (float) – Synchrotron angular frequency.
landau (numpy.ndarray) – Landau thresholds from landau_threshold; only the dipole entry landau[0] is used.
- Returns
True if HOM-driven coupled-bunch unstable.
- Return type
bool
- Raises
ValueError – If f_HOM and Z_HOM have mismatched lengths.
References
Eq. (22) in [1].
albums.physics.ptbl
Periodic transient beam loading (PTBL) (also called coupled bunch mode l=±1 instability).
Three backends:
ptbl_he: He’s perturbation criterion [1].
ptbl_alves: Gaussian longitudinal mode-coupling instabilty method [2].
coupled_bunch_mode1: Bosch [1] l=±1 coupled-bunch dipole mode [3].
References
- [1] He, Tianlong. “Novel perturbation method for judging the stability of the
equilibrium solution in the presence of passive harmonic cavities.” Physical Review Accelerators and Beams 25.9 (2022): 094402.
- [2] Alves, Murilo B. “Theoretical models for longitudinal coupled-bunch instabilities
driven by harmonic cavities in electron storage rings.” Physical Review Accelerators and Beams 28.3 (2025): 034401.
- [3] He, Tianlong. “Novel perturbation method for judging the stability of the
equilibrium solution in the presence of passive harmonic cavities.” Physical Review Accelerators and Beams 25.9 (2022): 094402.
- ptbl_he(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, PHI: np.ndarray) bool[source]
PTBL stability test via He’s perturbation criterion (eta > 1).
- Parameters
ring (Synchrotron) – Ring parameters (uses h, T0).
cavity_list (list of CavityResonator) – Solved cavities (main then harmonic).
I0 (float) – Beam current in A.
F (numpy.ndarray) – Amplitude form factor per cavity (F[1] is the harmonic cavity).
PHI (numpy.ndarray) – Phase form factor per cavity (PHI[1] is the harmonic cavity).
- Returns
True if PTBL-unstable (eta > 1).
- Return type
bool
References
He [1].
- coupled_bunch_mode1_damping_rate(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, Omega: float, mu: int, bunch_length: float) float[source]
Damping rate of the l=±1 coupled-bunch mode. Eq. (15) in [3].
- coupled_bunch_mode1(ring: Synchrotron, cavity_list: list[CavityResonator], I0: float, F: np.ndarray, omega_r: float, bunch_length: float, landau_threshold: np.ndarray) tuple[np.ndarray, np.ndarray, np.ndarray][source]
Coupled-bunch dipole mode l=±1 (Bosch mode-1 criterion).
- Parameters
ring (Synchrotron) – Ring parameters.
cavity_list (list of CavityResonator) – Solved cavities.
I0 (float) – Beam current in A.
F (numpy.ndarray) – Amplitude form factor per cavity.
omega_r (float) – Synchrotron angular frequency.
bunch_length (float) – RMS bunch length in [s].
landau_threshold (numpy.ndarray) – Per-mode thresholds from landau_threshold.
- Returns
coupled_mode1 (numpy.ndarray of bool, shape (2,)) – Instability flag for the +1 and -1 modes.
modes (numpy.ndarray, shape (2,)) – Coherent angular frequency for each mode.
converged (numpy.ndarray of bool, shape (2,)) – Root-finder convergence per mode.
References
Eq. (15) in [3].
- prepare_alves_le(ring: Synchrotron, LE: LongitudinalEquilibrium) None[source]
Set the synchrotron tune from the bunch length and select ImpedanceDFT.
- ptbl_alves(ring: Synchrotron, LE: LongitudinalEquilibrium, max_azi: int = 10, max_rad: int = 10) tuple[bool, float][source]
PTBL via Gaussian longitudinal mode-coupling instability method (coupled-bunch mode 1).
Also flag the usual coupled-bunch instability of mode 1 as PTBL.
- Parameters
ring (Synchrotron) – Ring parameters (uses omega1, tau).
LE (LongitudinalEquilibrium) – Solved pycolleff equilibrium handle (Equilibrium.backend_LE).
max_azi (int, optional) – Maximum azimuthal mode number (default 10).
max_rad (int, optional) – Maximum radial mode number (default 10).
- Returns
unstable (bool) – True if the largest net growth rate is positive.
growth (float) – Net growth rate (eigenvalue imaginary part minus radiation damping).
References
Alves [2].