API reference

This section documents the public Python API of barc4beams. Most users will interact primarily with the barc4beams.beam.Beam container and a few high-level helper functions, but all modules are listed for completeness.

Beam container

beam.py — unified interface classes for standardized beams.

Beam

Single standardized photon beam.

BeamEnsemble

Collection of comparable beam realizations, typically repeated seeds/runs of the same simulation setup, used for ensemble statistics.

class barc4beams.beam.Beam(obj: Any, code: str | None = None)

Bases: object

High-level container for one standardized photon beam.

Wraps a validated beam DataFrame and exposes core analysis, propagation, sampling, saving, and visualization methods.

apply_wavefront(*, wavefront: dict, energy: float | None = None, wavelength: float | None = None, threshold: float | None = None, verbose: bool = False) Beam

Returns a new Beam instance with updated intensity, slopes, and lost-ray flags.

caustic(*, n_points: int = 501, start: float = -0.5, finish: float = 0.5) dict

Compute the free-space caustic of this Beam.

See propagation.caustic.

property df: DataFrame

Standardized beam DataFrame.

classmethod from_df(df: DataFrame) Beam

Create a Beam directly from a standard DataFrame.

classmethod from_h5(path: str) Beam

Load a Beam from an HDF5 file written by io.save_beam.

classmethod from_intensity(*, far_field: dict, near_field: dict | None = None, n_rays: int, energy: float | None = None, wavelength: float | None = None, jitter: bool = True, threshold: float | None = None, seed: int | None = 42, z0: float = 0.0, polarization_degree: float = 1.0) Beam

Build a Beam by sampling 2D intensity maps.

See sampling.beam_from_intensity.

classmethod from_wavefront(*, wavefront: dict, n_rays: int, energy: float | None = None, wavelength: float | None = None, jitter: bool = True, threshold: float | None = None, seed: int | None = 42, z0: float = 0.0, polarization_degree: float = 1.0) Beam

Build a Beam by sampling a spatial wavefront map.

See sampling.beam_from_wavefront.

plot_beam(*, mode: str = 'scatter', aspect_ratio: bool = True, color: int = 1, x_range: tuple[float | None, float | None] | None = None, y_range: tuple[float | None, float | None] | None = None, bins: int | Tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, showXhist: bool = True, showYhist: bool = True, envelope: bool = False, envelope_method: str = 'edgeworth', apply_style: bool = True, k: float = 1.0, z_offset: float = 0.0, scatter_weight_mode: str = 'auto', plot: bool = True)

Plot the spatial footprint X vs Y with optional propagation offset.

plot_caustic(*, which: Literal['x', 'y', 'both'] = 'both', aspect_ratio: bool = False, color: int | None = 5, z_range: tuple[float | None, float | None] | None = None, xy_range: tuple[float | None, float | None] | None = None, bins: int | tuple[int | None, int] | None = None, bin_width: float | None = None, dpi: int = 100, path: str | None = None, apply_style: bool = True, k: float = 1.0, top_stat: str | None = None, n_points: int = 501, start: float = -0.5, finish: float = 0.5, plot: bool = True)

Plot the caustic map computed from self.caustic().

plot_divergence(*, mode: str = 'scatter', aspect_ratio: bool = False, color: int = 2, x_range: tuple[float | None, float | None] | None = None, y_range: tuple[float | None, float | None] | None = None, bins: int | tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, showXhist: bool = True, showYhist: bool = True, envelope: bool = False, envelope_method: str = 'edgeworth', apply_style: bool = True, k: float = 1.0, scatter_weight_mode: str = 'auto', plot: bool = True)

Plot the angular distribution dX vs dY.

plot_energy(*, bins: int | tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, apply_style: bool = True, k: float = 1.0, plot: bool = True)

Plot the energy distribution of the beam.

plot_energy_vs_intensity(*, mode: str = 'scatter', aspect_ratio: bool = False, color: int | None = 3, x_range: tuple[float | None, float | None] | None = None, y_range: tuple[float | None, float | None] | None = None, bins: int | tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, showXhist: bool = True, showYhist: bool = True, envelope_method: str = 'edgeworth', apply_style: bool = True, k: float = 1.0, scatter_weight_mode: str = 'auto', plot: bool = True)

Plot beam intensity as a function of photon energy.

plot_intensity(*, bins: int | tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, apply_style: bool = True, k: float = 1.0, plot: bool = True)

Plot the intensity distribution of the beam.

plot_phase_space(*, direction: str = 'both', mode: str = 'scatter', aspect_ratio: bool = False, color: int = 3, x_range: tuple[float | None, float | None] | None = None, y_range: tuple[float | None, float | None] | None = None, bins: int | tuple[int, int] | None = None, bin_width: float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, showXhist: bool = True, showYhist: bool = True, envelope: bool = False, envelope_method: str = 'edgeworth', apply_style: bool = True, k: float = 1.0, z_offset: float = 0.0, scatter_weight_mode: str = 'auto', plot: bool = True)

Plot phase-space diagrams X vs dX and/or Y vs dY.

propagate(z_offset: float, *, verbose: bool = False) Beam

Return a new Beam propagated through free space by z_offset [m].

save(path: str, *, meta: dict[str, Any] | None = None) None

Save beam to HDF5 and stats to JSON.

The HDF5 file contains the beam. A sibling JSON file with the same base name contains the statistics.

save_beam(path: str) None

Save the beam only to HDF5.

save_stats(path: str, *, meta: dict[str, Any] | None = None) None

Save statistics only to JSON.

stats(*, verbose: bool = False) dict

Compute descriptive beam statistics.

See stats.get_statistics.

class barc4beams.beam.BeamEnsemble(beams: Sequence[Beam | DataFrame | Any], code: str | None = None)

Bases: object

Container for comparable standardized beam realizations.

This is intended for repeated runs/seeds of the same beamline setup. It owns ensemble-level statistics, saving, and merging. Single-beam operations such as plotting, propagation, and caustic calculation remain on Beam.

classmethod from_dfs(beams: Sequence[DataFrame]) BeamEnsemble

Create a BeamEnsemble directly from standard DataFrames.

classmethod from_h5(path: str) BeamEnsemble

Load a BeamEnsemble from an HDF5 file written by io.save_beam_ensemble.

merge() Beam

Merge all ensemble runs into a single Beam.

The returned object is a Beam instance.

property n_runs: int

Number of beam realizations in the ensemble.

property runs: Sequence[DataFrame]

Standardized beam DataFrames.

save(path: str, *, meta: dict[str, Any] | None = None) None

Save ensemble beams to HDF5 and ensemble stats to JSON.

The HDF5 file contains all runs. A sibling JSON file with the same base name contains ensemble statistics.

save_beams(path: str) None

Save ensemble beams only to HDF5.

save_stats(path: str, *, meta: dict[str, Any] | None = None) None

Save ensemble statistics only to JSON.

stats(*, verbose: bool = False) dict

Compute ensemble statistics over all runs.

See stats.get_statistics.

Propagation

propagation.py - free space ray tracing.

barc4beams.propagation.caustic(beam: DataFrame, *, n_points: int = 501, start: float = -0.5, finish: float = 0.5) dict

Compute free-space caustics for a standard beam.

Ray positions are propagated in free space. Ray intensity weights are not modified by propagation and are used for all per-plane statistics.

barc4beams.propagation.propagate(beam: DataFrame, z_offset: float) DataFrame

Compute free-space propagation for a standard beam

Performs:

X <- X + z_offset * dX Y <- Y + z_offset * dY

Parameters:
  • beam (pandas.DataFrame) – Standardized beam. Validated via schema.validate_beam(beam).

  • z_offset (float) – Propagation distance in meters (positive downstream).

Returns:

Standard beam at the propagated plane.

Return type:

pandas.DataFrame

Sampling

sampling.py — generate a standardized beam by sampling 2D intensity maps.

barc4beams.sampling.apply_wavefront(*, standard_beam: DataFrame, wavefront: dict, energy: float | None = None, wavelength: float | None = None, threshold: float | None = None) DataFrame

Apply a spatial wavefront map to an existing standard beam.

The input beam is copied. Ray positions are preserved. The wavefront intensity is interpolated at each ray position and applied as a multiplicative transmission factor. The wavefront phase gradient is interpolated at each ray position and applied as an angular kick:

dX_out = dX_in + (1 / k) * dphi/dx dY_out = dY_in + (1 / k) * dphi/dy

with k = 2*pi / wavelength.

Rays outside the wavefront grid, rays landing on zero/invalid transmission, and rays landing where the phase-gradient support is invalid are marked as lost and assigned zero intensity.

Parameters:
  • standard_beam (pandas.DataFrame) – Standard beam DataFrame.

  • wavefront (dict) –

    Flat dict with keys:
    • ”intensity”: 2D array I[y, x].

    • ”phase”: 2D array of unwrapped phase in radians.

    • ”x_axis”: 1D array of x in meters.

    • ”y_axis”: 1D array of y in meters.

  • energy (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • wavelength (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • threshold (float or None, optional) – Relative cutoff in [0, 1]. Pixels below threshold * max(intensity) are treated as invalid support.

Returns:

New standard beam DataFrame with updated intensity, slopes, and lost-ray flags.

Return type:

pandas.DataFrame

Raises:

ValueError – If the input beam or wavefront is invalid.

barc4beams.sampling.beam_from_intensity(*, far_field: dict, near_field: dict | None = None, n_rays: int, energy: float | None = None, wavelength: float | None = None, jitter: bool = True, threshold: float | None = None, seed: int | None = 42, z0: float = 0.0, polarization_degree: float = 1.0) DataFrame

Build a standard beam by sampling intensity maps (SI units only).

Parameters:
  • far_field (dict) – Flat dict with keys: {“intensity”, “x_axis”, “y_axis”}. - “intensity”: 2D array Iff[y, x] (already per pixel; no unit conversion here) - “x_axis”: 1D array of xp in radians (strictly monotonic) - “y_axis”: 1D array of yp in radians (strictly monotonic) This is REQUIRED and defines (dX, dY).

  • near_field (dict or None, optional) – Flat dict with keys: {“intensity”, “x_axis”, “y_axis”}. - “intensity”: 2D array Inf[y, x] (already per pixel) - “x_axis”: 1D array of x in meters (strictly monotonic) - “y_axis”: 1D array of y in meters (strictly monotonic) If provided, defines (X, Y); otherwise X=Y=0 (point source at z0).

  • n_rays (int) – Number of rays to sample.

  • energy (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • wavelength (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • jitter (bool, optional) – Sub-pixel jitter for both FF and NF maps (if NF present).

  • threshold (float or None, optional) – Relative cutoff in [0, 1] applied independently to each map.

  • seed (int | None, optional) – RNG seed. If both FF and NF are sampled, NF uses (seed+1) for decorrelation.

  • z0 (float, default 0.0) – Source plane position assigned to all rays (Z=z0, dZ=0).

  • polarization_degree (float, default 1.0) – Value in [0,1] is the s-polarization fraction: Is = pdeg, Ip = 1-pdeg

Returns:

Standard beam DataFrame ready for plotting/propagation/caustic.

Return type:

pandas.DataFrame

Notes

The sampling algorithm implemented here follows the strategy described in Rebuffi et al., J. Synchrotron Rad. 27, 1108–1120 (2020).

barc4beams.sampling.beam_from_wavefront(*, wavefront: dict, n_rays: int, energy: float | None = None, wavelength: float | None = None, jitter: bool = True, threshold: float | None = None, seed: int | None = 42, z0: float = 0.0, polarization_degree: float = 1.0) DataFrame

Build a standard beam by sampling a spatial wavefront map (SI units only).

The ray positions (X, Y) are sampled from the wavefront intensity map. The local ray angles (dX, dY) are obtained from the phase gradient:

dX = (1 / k) * dphi/dx dY = (1 / k) * dphi/dy

with k = 2*pi / wavelength.

Parameters:
  • wavefront (dict) –

    Flat dict with keys:
    • ”intensity”: 2D array I[y, x].

    • ”phase”: 2D array of unwrapped phase in radians.

    • ”x_axis”: 1D array of x in meters.

    • ”y_axis”: 1D array of y in meters.

  • n_rays (int) – Number of rays to sample.

  • energy (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • wavelength (float, optional) – Exactly one must be provided. The other is computed using misc.energy_wavelength(…). If ‘energy’ is given, wavelength is computed in meters; if ‘wavelength’ is given, energy is computed in eV.

  • jitter (bool, optional) – Sub-pixel jitter for the sampled (X, Y) coordinates.

  • threshold (float or None, optional) – Relative cutoff in [0, 1]. Pixels below threshold * max(intensity) are excluded both from position sampling and from phase-gradient support.

  • seed (int | None, optional) – RNG seed for reproducibility. Use an int for deterministic draws; use None for non-deterministic sampling.

  • z0 (float, default 0.0) – Source plane position assigned to all rays (Z=z0, dZ=0).

  • polarization_degree (float, default 1.0) – Value in [0, 1] is the s-polarization fraction: Is = pdeg, Ip = 1-pdeg.

Returns:

Standard beam DataFrame ready for plotting/propagation/caustic.

Return type:

pandas.DataFrame

Notes

This function samples ray positions from a spatial intensity map and assigns local propagation angles from the phase gradient.

Low-intensity or invalid pixels are masked internally before gradient evaluation. This avoids differentiating noisy finite phase values outside the useful wavefront support.

Statistics

stats.py - beam statistics and 1D profile metrics.

barc4beams.stats.calc_centroid_from_particle_distribution(profile: ndarray, weights: ndarray | None = None) float

Compute the centroid (center of mass) of a 1D particle-position distribution.

This treats profile as Monte Carlo samples of positions (each sample has equal weight by default). If weights are provided (e.g., per-ray intensities), a weighted centroid is computed.

Parameters:
  • profile (np.ndarray) – 1D array of particle positions (e.g., X or Y).

  • weights (np.ndarray, optional) – Non-negative weights for each sample (same shape as profile). If None, all samples are equally weighted.

Returns:

Centroid in the same units as profile, or np.nan if it cannot be computed (e.g., empty or all-nonfinite inputs, or zero total weight).

Return type:

float

barc4beams.stats.calc_envelope_from_moments(mean: float, std: float, skewness: float, kurtosis_excess: float, axis: ndarray, method: str = 'edgeworth', clip_negative: bool = True, maxent_iters: int = 2000, maxent_lr: float = 0.001, seed: int | None = None) Dict

Construct an approximate 1D PDF envelope consistent with the first four moments.

Parameters:
  • mean (float) – Mean (μ) of the target distribution.

  • std (float) – Standard deviation (σ > 0).

  • skewness (float) – Standardized 3rd moment γ1.

  • kurtosis_excess (float) – Excess kurtosis γ2 (kurtosis − 3).

  • axis (np.ndarray) – 1D grid where the envelope is evaluated.

  • method ({'edgeworth', 'pearson', 'maxent'}, default 'edgeworth') –

    • ‘edgeworth’: Gram–Charlier/Edgeworth expansion around N(μ, σ²) up to H6.

    • ’pearson’ : Pearson Type III (Gamma) matched to γ1; reflect for γ1<0.

    • ’maxent’Discrete maximum-entropy pdf ~ exp(a0 + a1 x + … + a4 x^4)

      fitted so moments up to order 4 match on the given axis.

  • clip_negative (bool, default True) – If True, clip negative pdf values to 0 and renormalize (useful for ‘edgeworth’).

  • maxent_iters (int, default 2000) – Iterations for the ‘maxent’ solver.

  • maxent_lr (float, default 1e-3) – Learning rate for the ‘maxent’ solver.

  • seed (int or None) – RNG seed (used only by ‘maxent’ initialization).

Returns:

{‘envelope’: pdf_vals, ‘axis’: axis}

Return type:

dict

Notes

  • Edgeworth (default) is fastest and smooth for |skew|≲1 and |excess kurtosis|≲2. Negative lobes can appear when moments are large; keep clip_negative=True to force a valid PDF.

  • Pearson Type III guarantees positivity and matches mean/σ/skewness exactly. The implied excess kurtosis is γ₂ = 1.5·γ₁²; the supplied kurtosis is ignored if inconsistent.

  • Maximum entropy finds the least-assumptive distribution subject to the moment constraints. It needs a wide, dense axis (e.g. μ±6σ) and is slower; increase maxent_iters or reduce maxent_lr if convergence is poor.

  • The four moments do not uniquely define a distribution. The returned envelope is only one of many possible PDFs consistent with them.

barc4beams.stats.calc_focal_distance_from_particle_distribution(position: ndarray, divergence: ndarray, weights: ndarray | None = None, *, eps: float = 1e-16, ridge: float = 0.0, huge_m: float = 1e+26) float

Compute the signed focal distance minimizing the weighted variance of position + x * divergence.

If weights is None, all particles are assigned unit weight.

Parameters:
  • position (np.ndarray) – 1D array of transverse positions, e.g. X or Y [m].

  • divergence (np.ndarray) – 1D array of corresponding angular components, e.g. dX or dY [rad].

  • weights (np.ndarray, optional) – 1D array of statistical ray weights. If None, unit weights are used.

  • eps (float, optional) – Numerical floor for denominator stability.

  • ridge (float, optional) – Extra ridge term added to the divergence variance.

  • huge_m (float, optional) – Finite surrogate distance for an effectively infinite focus.

Returns:

Signed focal distance in meters.

Return type:

float

barc4beams.stats.calc_fwhm_from_particle_distribution(profile: ndarray, weights: ndarray | None = None, bins: int | None = None) float

Calculate the FWHM of a 1D particle distribution.

If weights is None, all particles are assigned unit weight. If weights are provided, the FWHM is computed from a weighted histogram.

Parameters:
  • profile (np.ndarray) – 1D array representing particle positions, divergences, or energies.

  • weights (np.ndarray, optional) – 1D array of statistical ray weights. If None, unit weights are used.

  • bins (int or None, optional) – Number of histogram bins. If None, an adaptive rule is used.

Returns:

FWHM value in the same units as profile. Returns -1.0 if computation fails.

Return type:

float

barc4beams.stats.calc_moments_from_particle_distribution(profile: ndarray, weights: ndarray | None = None) Tuple[float, float, float, float]

Return (mean, std, skewness, kurtosis_excess) using population definitions.

If weights is None, all particles are assigned unit weight. If weights are provided, the moments are intensity-weighted.

Parameters:
  • profile (np.ndarray) – 1D array representing particle positions, divergences, or energies.

  • weights (np.ndarray, optional) – 1D array of statistical ray weights. If None, unit weights are used.

Returns:

Mean, standard deviation, skewness, and excess kurtosis.

Return type:

tuple[float, float, float, float]

barc4beams.stats.get_focal_distance(beam: DataFrame, verbose: bool = False, direction: str = 'both', eps: float = 1e-16, ridge: float = 0.0, huge_m: float = 1e+23) Dict[str, float]

Calculate the intensity-weighted focal distance along X and Y.

Lost rays are removed via lost_ray_flag == 0 before computing the focal distance. If the intensity column is present, it is used as the ray weight. Otherwise, all rays are assigned unit weight.

Uses the closed-form weighted least-squares expression:

x* = -Cov_w(axis, d_axis) / (Var_w(d_axis) + ridge)

Parameters:
  • beam (pandas.DataFrame) – Beam dataframe containing X/dX and/or Y/dY columns.

  • verbose (bool, optional) – If True, prints diagnostic information.

  • direction ({'x', 'y', 'both'}, optional) – Direction to optimize.

  • eps (float, optional) – Numerical floor for denominator stability.

  • ridge (float, optional) – Extra ridge term added to the divergence variance.

  • huge_m (float, optional) – Finite surrogate distance for an effectively infinite focus.

Returns:

Dictionary with keys 'fx' and 'fy'.

Return type:

dict

barc4beams.stats.get_statistics(beams: DataFrame | List[DataFrame], *, verbose: bool = False) dict

Compute intensity-weighted beam statistics for X/Y, dX/dY, and energy.

Lost rays are removed via lost_ray_flag == 0 before computing stats. All statistical observables are weighted by the intensity column.

With unit intensities, the weighted formulas reduce to the unweighted case.

Inputs

beamspd.DataFrame or list[pd.DataFrame]

One or multiple barc4beams beam DataFrames.

keyword verbose:

If True, print a human-readable summary.

kwtype verbose:

bool, optional

returns:
{
“meta”: {

“n_rays”: int, “n_repetitions”: int, “good_rays”: [mean, std], “transmission”: [mean%, std%],

}, “energy”: {“mean”:[val,std], “std”:[val,std], “fwhm”:[val,std]}, “X”: {“mean”:[val,std], “std”:[val,std],

“fwhm”:[val,std], “skewness”:[val,std], “kurtosis”:[val,std]},

“Y”: { … same keys as X … }, “dX”: { … same keys as X … }, “dY”: { … same keys as X … }, “fx”: [val,std], “fy”: [val,std],

}

Only keys for columns actually present in the input are included.

rtype:

dict

I/O utilities

io.py - saving and loading of standardised beams and stats.

barc4beams.io.read_beam(path: str) DataFrame

Read a standardized beam from an HDF5 file.

Parameters:

path (str) – Input HDF5 file path.

Returns:

Beam as a DataFrame.

Return type:

pandas.DataFrame

Raises:
  • KeyError – If the ‘beam’ group or required datasets are missing.

  • ValueError – If the reconstructed DataFrame fails validation.

barc4beams.io.read_beam_ensemble(path: str) list[DataFrame]

Read an ensemble of standardized beams from an HDF5 file.

Parameters:

path (str) – Input HDF5 file path.

Returns:

List of standardized beams, one DataFrame per run.

Return type:

list[pandas.DataFrame]

Raises:
  • KeyError – If the ensemble groups or beam datasets are missing.

  • ValueError – If any reconstructed beam fails validation.

barc4beams.io.read_json_stats(path: str) Dict[str, Any]

Load a JSON file saved by save_json_stats.

Returns:

Record with keys: created_utc, meta, stats

Return type:

dict

barc4beams.io.save_beam(obj: Any, path: str, *, code: str | None = None, overwrite: bool = True, chunks: bool = True) None

Save a standardized beam to an HDF5 file.

Parameters:
  • obj (Any) – Beam-like object. If a pandas.DataFrame, it is assumed to be already standardized. Otherwise it is converted via adapters.to_standard_beam(obj, code=code).

  • path (str) – Output HDF5 file path.

  • code (str, optional) – Backend hint for conversion (passed to to_standard_beam).

  • overwrite (bool, optional) – If False and path exists, raise an error. Default is True.

  • chunks (bool, optional) – Enable chunked datasets (recommended). Default True.

Raises:
  • ValueError – If standardization/validation fails or no numeric columns found.

  • FileExistsError – If overwrite is False and file already exists.

barc4beams.io.save_beam_ensemble(objs: list[Any], path: str, *, code: str | None = None, overwrite: bool = True, chunks: bool = True) None

Save an ensemble of standardized beams to an HDF5 file.

Parameters:
  • objs (list[Any]) – Beam-like objects. Each item may be a standardized pandas.DataFrame or any object accepted by adapters.to_standard_beam(obj, code=code).

  • path (str) – Output HDF5 file path.

  • code (str, optional) – Backend hint for conversion, passed to to_standard_beam for non-DataFrame objects.

  • overwrite (bool, optional) – If False and path exists, raise an error. Default is True.

  • chunks (bool, optional) – Enable chunked datasets. Default True.

Raises:
  • ValueError – If the ensemble is empty, standardization/validation fails, or a beam has no numeric columns.

  • FileExistsError – If overwrite is False and file already exists.

barc4beams.io.save_json_stats(stats: Dict[str, Any], path: str, *, meta: Dict[str, Any] | None = None) str

Save a get_statistics() dictionary to JSON.

Parameters:
  • stats (dict) – The dictionary returned by get_statistics(…).

  • path (str) – Target JSON file path.

  • meta (dict, optional) – Extra metadata to embed (e.g., n_seeds, n_rays, code_sha, settings).

Returns:

The path written.

Return type:

str

Visualization

viz.py - plotting routines for beams and beamline layouts.

barc4beams.viz.plot() None

Show all pending figures.

barc4beams.viz.plot_beam(df: DataFrame, *, mode: str = 'scatter', aspect_ratio: bool = True, color=1, x_range=None, y_range=None, bins=None, bin_width=None, bin_method=0, dpi: int = 100, path: str | None = None, showXhist=True, showYhist=True, envelope=False, envelope_method='edgeworth', weight_by_intensity: bool = True, apply_style: bool = True, k: float = 1.0, plot: bool = True, z_offset: float = 0.0, scatter_weight_mode: Literal['auto', 'none', 'resample', 'color', 'alpha', 'threshold'] | str = 'auto', scatter_sample_size: int | None = None, scatter_seed: int | None = 12345, scatter_threshold: float = 0.0)

Plot the spatial footprint of a standardized beam (X vs Y), with optional marginals and moment-matched envelope overlays.

Parameters:
  • df (pandas.DataFrame) – Standardized beam with columns: ‘X’,’Y’,’dX’,’dY’,’lost_ray_flag’ (0=alive). Units expected in meters (pos) and radians (angles). This function scales to µm/µrad.

  • mode ({'scatter','histo2d', ...}, default 'scatter') – Plot style. Aliases like ‘s’/’h’ are accepted and normalized.

  • aspect_ratio (bool, default True) – If True, main axes uses equal aspect.

  • color (int or None, default 1) – Legacy color scheme index. 0/None → monochrome points; 1..4 → colormaps.

  • x_range ((min, max) or None) – Data limits. If None/partial, auto-detected with a small padding.

  • y_range ((min, max) or None) – Data limits. If None/partial, auto-detected with a small padding.

  • bins (int or (x_bins, y_bins) or None) – Histogram binning for the marginals and hist2d. Auto if None.

  • bin_width (float or None) – If given, overrides bin count as ceil(range/bin_width).

  • bin_method (int, default 0) – Auto-binning rule: 0=sqrt, 1=Sturges, 2=Rice, 3=Doane.

  • dpi (int, default 300)

  • path (str or None) – If provided, the figure is saved.

  • showXhist (bool, default True) – Whether to show X/Y marginals.

  • showYhist (bool, default True) – Whether to show X/Y marginals.

  • envelope (bool, default True) – Overlay envelope curve on the 1D marginals using moments from the data.

  • envelope_method ({'edgeworth','pearson','maxent'}, default 'edgeworth') – Reconstruction method passed to stats.calc_envelope_from_moments.

  • apply_style (bool, default True) – Call start_plotting(k) before plotting.

  • k (float, default 1.0) – Global style scale factor.

Returns:

The Matplotlib figure and axes.

Return type:

fig, (ax_image, ax_histx, ax_histy)

barc4beams.viz.plot_caustic(caustic: dict, *, which: Literal['x', 'y', 'both'] = 'both', aspect_ratio: bool = False, color: int | None = 5, z_range: Tuple[int | float | None, int | float | None] | None = None, xy_range: Tuple[int | float | None, int | float | None] | None = None, bins: int | Tuple[int, int] | None = None, bin_width: int | float | None = None, dpi: int = 100, path: str | None = None, apply_style: bool = True, k: float = 1.0, plot: bool = True, top_stat: str | None = None)

Plane-centered 2D histogram caustic (no other modes allowed).

  • Z is binned with one contiguous column per plane (no gaps).

  • X/Y use fixed bin width (if bin_width) or a fixed number of bins (bins).

  • Optional top panel shows FWHM or sigma (STD) vs z.

Notes

  • Units: position on the map is in µm (input arrays in meters are scaled by 1e6).

  • Large beams are safe: uses numpy.histogram2d + pcolormesh (no KDE, no scatter).

barc4beams.viz.plot_divergence(df: DataFrame, *, mode: str = 'scatter', aspect_ratio: bool = False, color=2, x_range=None, y_range=None, bins=None, bin_width=None, bin_method=0, dpi: int = 100, path: str | None = None, showXhist=True, showYhist=True, envelope=False, envelope_method='edgeworth', weight_by_intensity: bool = True, apply_style: bool = True, k: float = 1.0, plot: bool = True, z_offset: float = 0.0, scatter_weight_mode: Literal['auto', 'none', 'resample', 'color', 'alpha', 'threshold'] | str = 'auto', scatter_sample_size: int | None = None, scatter_seed: int | None = 12345, scatter_threshold: float = 0.0)

Plot the beam divergence (dX vs dY) in µrad with optional marginals and envelopes. (See plot_beam for parameter semantics.)

Return type:

fig, (ax_image, ax_histx, ax_histy)

barc4beams.viz.plot_energy(df: DataFrame, *, bins: int | Tuple[int, int] | None = None, bin_width: int | float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, weight_by_intensity: bool = True, apply_style: bool = True, k: float = 1.0, plot: bool = True) Tuple[Figure, Axes]

Energy distribution vs E (eV), optionally intensity-weighted.

barc4beams.viz.plot_energy_vs_intensity(df: DataFrame, *, mode: str = 'scatter', aspect_ratio: bool = False, color: int | None = 3, x_range: Tuple[int | float | None, int | float | None] | None = None, y_range: Tuple[int | float | None, int | float | None] | None = None, bins: int | Tuple[int, int] | None = None, bin_width: int | float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, showXhist: bool = True, showYhist: bool = True, envelope_method: str = 'edgeworth', weight_by_intensity: bool = True, apply_style: bool = True, k: float = 1.0, plot: bool = True, scatter_weight_mode: Literal['auto', 'none', 'resample', 'color', 'alpha', 'threshold'] | str = 'auto', scatter_sample_size: int | None = None, scatter_seed: int | None = 12345, scatter_threshold: float = 0.0) Tuple[Figure, Tuple[Axes, Axes | None, Axes | None]]

2D plot with X=energy [eV], Y=Intensity [arb], with optional marginals/envelopes; never silently shows.

barc4beams.viz.plot_intensity(df: DataFrame, *, bins: int | Tuple[int, int] | None = None, bin_width: int | float | None = None, bin_method: int = 0, dpi: int = 100, path: str | None = None, weight_by_intensity: bool = False, apply_style: bool = True, k: float = 1.0, plot: bool = True) Tuple[Figure, Axes]

Intensity distribution vs I, optionally intensity-weighted.

barc4beams.viz.plot_phase_space(df: DataFrame, *, direction: str = 'both', mode: str = 'scatter', aspect_ratio: bool = False, color=3, x_range=None, y_range=None, bins=None, bin_width=None, bin_method=0, dpi: int = 100, path: str | None = None, showXhist=True, showYhist=True, envelope=False, envelope_method='edgeworth', weight_by_intensity: bool = True, apply_style: bool = True, k: float = 1.0, plot: bool = True, z_offset: float = 0.0, scatter_weight_mode: Literal['auto', 'none', 'resample', 'color', 'alpha', 'threshold'] | str = 'auto', scatter_sample_size: int | None = None, scatter_seed: int | None = 12345, scatter_threshold: float = 0.0)

Plot phase space for one or both planes: (X vs dX) and/or (Y vs dY), in µm/µrad.

Returns:

  • (fig_x, axes_x), (fig_y, axes_y) if direction=’both’

  • or

  • fig, (ax_image, ax_histx, ax_histy)

barc4beams.viz.plotting_style(k: float = 1.0)

Temporary plotting style (restores previous rcParams on exit).

Examples

>>> with plotting_style(1.2):
...     plot_beam(df)
barc4beams.viz.start_plotting(k: float = 1.0) None

Set global Matplotlib plot parameters scaled by factor k.

Parameters:

k (float, optional) – Scaling factor for font sizes (1.0 = baseline).

Adapters

adapters.py - conversion of external beam data (PyOptiX, SHADOW3, SHADOW4) into the standard beam schema.

barc4beams.adapters.merge_standard_beams(beams: List[DataFrame]) DataFrame

Merge multiple standard photon beams (pandas DataFrames) into a single combined beam. Each input beam should already be standardized via to_standard_beam, The merge is performed by simple row-wise concatenation of all beams.

Args:

beams (list of pd.DataFrame): List of DataFrames to merge.

Returns:
pd.DataFrame: A single DataFrame containing all rows from the input beams.

Columns are the union of all input columns;

barc4beams.adapters.to_standard_beam(beam, code: str | None = None) DataFrame

Convert an external beam representation into the standard schema.

Supported inputs

  • PyOptiX beam (pd.DataFrame): typically from: OpticalElement.get_diagram(…) OpticalElement.get_impacts(…).

  • Shadow3 beam (code in {‘shadow3’,’s3’}):
    Uses beam.getshcol([…]) with indices:

    [11, 1, 3, 2, 4, 6, 5, 19, 23, 10, 24, 25]

    and returns a DataFrame with columns:
    [“energy”,”X”,”Y”,”Z”,”dX”,”dY”,”dZ”,”wavelength”,

    “intensity”,”lost_ray_flag”,”intensity_s-pol”,”intensity_p-pol”]

  • Shadow4 beam (code in {‘shadow4’,’s4’,’shadow’}):
    Uses beam.get_columns([…]) with indices:

    [26, 1, 3, 2, 4, 6, 5, 19, 23, 10, 24, 25]

    with the same output columns and clipping as Shadow3.

param beam:

PyOptiX DataFrame OR Shadow3/4 beam object.

type beam:

object

param code:

Explicit backend. If None, auto-detect.

type code:

{“pyoptix”, “shadow3”, “shadow4”, “s3”, “s4”}, optional

rtype:

pandas.DataFrame

Schema

schema.py - definition and validation of the standard beam format.

barc4beams.schema.validate_beam(df: DataFrame) None

Validate a standardized beam DataFrame.

Parameters:

df (pandas.DataFrame) – Beam after to_standard_beam(…). Columns may appear in any order.

Raises:

ValueError – If required columns are missing, intensity columns are out of [0, 1], lost-ray flags are not {0, 1}, or a lost ray has nonzero intensity.

Miscellaneous helpers

misc.py - optical design and other auxiliary functions.

barc4beams.misc.energy_wavelength(value: float, unit: str) float

Converts energy to wavelength and vice versa.

Parameters:

value (float or array-like): The value of either energy or wavelength. unity (str): {‘eV’,’meV’,’keV’,’m’, ‘um’,’µm’, ‘nm’,’A’,’Å’,’Angstrom’,} (case-insensitive)

Returns:

float: Converted value in meters if the input is energy, or in eV if the input is wavelength.

Raises:

ValueError: If an invalid unit is provided.