API reference

The symbols below are re-exported from the top-level ebsdsim package.

Simulation

Public API for EBSD master-pattern generation.

Ångström Cell / Atom in; conversion to nm SimCell happens once in ebsdsim.crystal.build. Default dynamical solver is Galerkin (RKSM).

class ebsdsim.api.Atom(element, x, y, z, occupancy=1.0, b_iso=None)[source]

Bases: object

Crystallographic site in fractional coordinates (direct lattice).

Parameters:
  • element (str) – Chemical symbol (e.g. "Ni", "Ga").

  • x (float) – Fractional coordinates in the direct unit cell.

  • y (float) – Fractional coordinates in the direct unit cell.

  • z (float) – Fractional coordinates in the direct unit cell.

  • occupancy (float, optional) – Site occupancy in [0, 1]. Default 1.0.

  • b_iso (float or None, optional) – Isotropic Debye–Waller factor in Ų. When None, a room-temperature default is used during structure-factor evaluation.

element: str
x: float
y: float
z: float
occupancy: float = 1.0
b_iso: float | None = None
__init__(element, x, y, z, occupancy=1.0, b_iso=None)
Parameters:
Return type:

None

class ebsdsim.api.Cell(a, b, c, alpha=90.0, beta=90.0, gamma=90.0, space_group=1)[source]

Bases: object

Unit-cell lattice parameters (Å and degrees).

Parameters:
  • a (float) – Lattice lengths in ångströms.

  • b (float) – Lattice lengths in ångströms.

  • c (float) – Lattice lengths in ångströms.

  • alpha (float, optional) – Interaxial angles in degrees. Default 90.0 each.

  • beta (float, optional) – Interaxial angles in degrees. Default 90.0 each.

  • gamma (float, optional) – Interaxial angles in degrees. Default 90.0 each.

  • space_group (int or str, optional) – International Tables space-group number or Hermann–Mauguin symbol. Default 1 (triclinic P1).

a: float
b: float
c: float
alpha: float = 90.0
beta: float = 90.0
gamma: float = 90.0
space_group: int | str = 1
__init__(a, b, c, alpha=90.0, beta=90.0, gamma=90.0, space_group=1)
Parameters:
Return type:

None

class ebsdsim.api.Material(cell, atoms, name='')[source]

Bases: object

Crystal specification for master-pattern simulation.

Parameters:
  • cell (Cell) – Unit-cell geometry and space group.

  • atoms (list of Atom) – Atomic sites in fractional coordinates.

  • name (str, optional) – Human-readable label stored in output metadata. Default "".

cell: Cell
atoms: list[Atom]
name: str = ''
to_simulation_cell()[source]

Build the internal simulation cell used by the GPU pipeline.

Return type:

SimCell

__init__(cell, atoms, name='')
Parameters:
Return type:

None

class ebsdsim.api.MasterPattern(pattern, integrated, n_k, n_sites, metadata=<factory>, bin_patterns=<factory>, bin_voltages_kv=<factory>, bin_weights=<factory>, kij=None, khat=None, pg_num=None, pg_symbol=None, data=<factory>, axes=<factory>)[source]

Bases: object

Rasterized master pattern and integration metadata.

pattern is the north-hemisphere Lambert raster (side, side) with side = 1 + 2 * halfw, equal to data[energy_int, site_int, 0]. It holds raw dynamical intensities; use lambert_data() for display scaling.

data is the dense Lambert tensor (E, S, H, side, side) of raw intensities. integrated and bin_patterns store fundamental-sector values (flattened (n_k * n_sites,)). Both lu_smith and Smith return len(bin_patterns) == len(bin_voltages_kv); the integrated total is a separate accumulator. Empty bin_patterns is the integrated-only edge case; voltages and weights remain energy-model metadata. kij and khat give fundamental-sector pixel indices and unit directions.

save / lambert_data are attached by ebsdsim.api so the engine layer does not import ebsdsim.io.

Parameters:
  • pattern (NDArray[float32])

  • integrated (NDArray[float32])

  • n_k (int)

  • n_sites (int)

  • metadata (dict[str, Any])

  • bin_patterns (list[NDArray[float32]])

  • bin_voltages_kv (list[float])

  • bin_weights (list[float])

  • kij (NDArray[int32] | None)

  • khat (NDArray[float32] | None)

  • pg_num (int | None)

  • pg_symbol (str | None)

  • data (NDArray[float32])

  • axes (dict[str, Any])

pattern: NDArray[float32]
integrated: NDArray[float32]
n_k: int
n_sites: int
metadata: dict[str, Any]
bin_patterns: list[NDArray[float32]]
bin_voltages_kv: list[float]
bin_weights: list[float]
kij: NDArray[int32] | None = None
khat: NDArray[float32] | None = None
pg_num: int | None = None
pg_symbol: str | None = None
data: NDArray[float32]
axes: dict[str, Any]
__init__(pattern, integrated, n_k, n_sites, metadata=<factory>, bin_patterns=<factory>, bin_voltages_kv=<factory>, bin_weights=<factory>, kij=None, khat=None, pg_num=None, pg_symbol=None, data=<factory>, axes=<factory>)
Parameters:
  • pattern (NDArray[float32])

  • integrated (NDArray[float32])

  • n_k (int)

  • n_sites (int)

  • metadata (dict[str, Any])

  • bin_patterns (list[NDArray[float32]])

  • bin_voltages_kv (list[float])

  • bin_weights (list[float])

  • kij (NDArray[int32] | None)

  • khat (NDArray[float32] | None)

  • pg_num (int | None)

  • pg_symbol (str | None)

  • data (NDArray[float32])

  • axes (dict[str, Any])

Return type:

None

lambert_data(*, normalize=None, robust_p_low=0.01, robust_p_high=0.99)

Expand raw FS intensities to Lambert (E, S, H, side, side).

Parameters:
  • normalize ({"minmax", "robust"} or None, optional) – Display scaling mode. None returns raw intensities unchanged.

  • robust_p_low (float, optional) – Percentile window used when normalize="robust".

  • robust_p_high (float, optional) – Percentile window used when normalize="robust".

  • self (MasterPattern)

Returns:

  • data (ndarray of float32) – Lambert tensor; see data for axis semantics.

  • axes (dict) – Index maps for energy, site, and hemisphere axes.

Return type:

tuple[NDArray[float32], dict[str, Any]]

save(path)

Write this master pattern (with intermediates) to a compressed .npz.

See ebsdsim.save_master_pattern() for the on-disk format.

Parameters:
Return type:

Path

ebsdsim.api.master_pattern(material, *, voltage_kv=20.0, halfw=500, dmin=0.05, energy_binwidth_keV=1.0, n_trajectories=1048576, sigma_deg=70.0, omega_deg=0.0, solver='galerkin', rank=8, exact_slow_cpu=False, verbosity=0, chunk_size=256, marginal_coverage=1.0, relative_image_stop=0.01, mc_backend='surrogate', bethe_c_strong=20.0, bethe_c_weak=40.0, bethe_c_cutoff=200.0, dbdiff_sg_cutoff=1.0, mc_auto_stop=True, mc_relative_tol=0.01, mc_min_trajectories=1048576, mc_max_trajectories=16777216)[source]

Generate an EBSD master pattern from a manual material specification.

Requires a WebGPU-capable GPU. Returns raw dynamical intensities; call MasterPattern.lambert_data() for display scaling.

Parameters:
  • material (Material) – Crystal structure and composition.

  • voltage_kv (float) – Beam energy in kV (default 20).

  • halfw (int) – Lambert half-width; side is 1 + 2 * halfw (default 500).

  • dmin (float) – Minimum interplanar spacing in nm (default 0.05).

  • energy_binwidth_keV (float) – Monte Carlo energy-bin width in keV (default 1).

  • n_trajectories (int) – MC trajectories per bin when mc_auto_stop=False.

  • sigma_deg (float) – Specimen tilt and azimuth (degrees).

  • omega_deg (float) – Specimen tilt and azimuth (degrees).

  • solver ({"galerkin", "smith", "lu_smith"}) – Dynamical backend (default galerkin). The legacy name "smith_iterative" is still accepted as a deprecated alias for "smith".

  • rank (int) – Krylov / Lyapunov rank (default 8 for Galerkin; smith requires 16, lu_smith accepts higher). Galerkin uses a fixed rank for every k-vector; there is no adaptive or per-k rank selection.

  • exact_slow_cpu (bool) – Full-rank CPU Lyapunov instead of GPU Smith.

  • verbosity ({0, 1, 2}) – Progress reporting level.

  • chunk_size (int) – GPU batch size for the multi-beam solve.

  • marginal_coverage (float) – Fraction of the MC energy distribution to integrate.

  • relative_image_stop (float) – Early-stop threshold on relative image change.

  • mc_backend ({"surrogate", "gpu"}) – Energy model (default surrogate).

  • bethe_c_strong (float) – Bethe perturbation cutoffs.

  • bethe_c_weak (float) – Bethe perturbation cutoffs.

  • bethe_c_cutoff (float) – Bethe perturbation cutoffs.

  • dbdiff_sg_cutoff (float) – Structure-factor inclusion threshold.

  • mc_auto_stop (bool) – Adaptive Monte Carlo trajectory count.

  • mc_relative_tol (float) – MC convergence tolerance.

  • mc_min_trajectories (int) – Bounds on adaptive MC trajectory count.

  • mc_max_trajectories (int) – Bounds on adaptive MC trajectory count.

Returns:

Lambert-rasterized result with per-bin intermediates and metadata.

Return type:

MasterPattern

ebsdsim.api.master_pattern_from_cif(path, **kwargs)[source]

Generate an EBSD master pattern from a CIF file or bundled preset.

path may be a filesystem path or a bundled preset name such as "GaN.cif" or "Ni.cif". The CIF is standardized to the International Tables setting on load (dual-origin groups use origin choice 2).

Accepts the same keyword arguments as master_pattern(). See Simulation parameters for the full parameter reference.

Parameters:
  • path (str or Path) – CIF file path or preset stem/name.

  • **kwargs – Forwarded to master_pattern() / SimParams.

Returns:

Lambert-rasterized result with per-bin intermediates and metadata.

Return type:

MasterPattern

Raises:
  • FileNotFoundError – If path does not resolve to a file or bundled preset.

  • ValueError – If the CIF is symmetry-inconsistent or the point group cannot be resolved.

Result container

MasterPattern is defined in the engine layer and re-exported from ebsdsim.api.

On-disk format

I/O layer: compressed .npz export of master patterns.

The on-disk format stores the fundamental-sector intensities only (the minimal, symmetry-reduced representation) and is always compressed. Per-energy bin intensity slices are written when MasterPattern.bin_patterns is non-empty (len(bin_patterns) == len(bin_voltages_kv) for both lu_smith and Smith). Smith runs also keep a separate device-accumulated integrated total; bin_voltages_kv / bin_weights remain the energy-model metadata. The embedded point-group operators and fundamental-sector normals make the file self-describing: it can be expanded back into full Lambert hemispheres with NumPy alone (see ebsdsim.io.load).

Arrays written

fundamental_sectorfloat32 (n_energy, n_site, n_k)

The symmetry-reduced intensities for every direction, packed along an energy axis and a site axis (raw, un-normalized). The energy axis is 1 + n_bins long when n_bins > 1 (index 0 is the energy-integrated weighted sum, index 1 + b is bin b) and length 1 otherwise (integrated-only when bin_patterns is empty, or a single stored bin). The site axis is 1 + n_sites long when n_sites > 1 (index 0 is the site mean, index 1 + s is site s) and length 1 otherwise. The north/south hemisphere of each of the n_k directions is carried by the sign column of fundamental_kij (the per-group N/S split is irregular, so hemisphere is not a separate array axis).

fundamental_kijint32 (n_k, 3)

Lambert pixel indices (i, j, sign) for each fundamental-sector direction (sign > 0 north, sign < 0 south).

fundamental_khatfloat32 (n_k, 3)

Unit propagation directions for each fundamental-sector pixel.

pg_operatorsfloat64 (n_ops, 3, 3)

Proper/improper point-group rotation matrices.

fs_normalsfloat64 (n_normals, 3)

Inward normals bounding the fundamental sector.

bin_voltages_kv / bin_weightsfloat32 (n_energy_bins,)

Dynamical voltage (kV) and energy weight of each energy-model bin. When per-bin patterns are stored their count matches this length; an empty bin_patterns list is the integrated-only edge case (no intensity slices).

site_weightsfloat32 (n_sites,)

Normalized occupancy × multiplicity weights used for the site-integrated marginal (index 0 on the site axis). Per-site slices are raw intensities.

meta_jsonuint8 (n_bytes,)

UTF-8 JSON metadata blob (decode with bytes(arr).decode("utf-8")).

ebsdsim.io.save.cell_metadata(cell)[source]

Serialize a SimCell to a JSON-friendly dict.

Per-site isotropic Debye–Waller factors are recorded in both Ų and nm² because they are commonly estimated and materially affect the pattern.

Parameters:

cell (SimCell)

Return type:

dict[str, Any]

ebsdsim.io.save.save_master_pattern(mp, path)[source]

Write a master pattern (with intermediates) to a compressed .npz.

The file stores symmetry-reduced fundamental-sector intensities plus embedded point-group operators so it can be expanded offline with ebsdsim.io.load.

Per-bin intensity slices are written when mp.bin_patterns is non-empty (same count contract as lu_smith / Smith: len(bin_patterns) == len(bin_voltages_kv)). Empty bin_patterns with non-empty bin_voltages_kv remains a legal integrated-only edge case: voltages/weights are energy-model metadata, not a claim that one pattern exists per voltage.

Parameters:
Returns:

Resolved output path.

Return type:

Path

ebsdsim.io.save.stack_bins(bin_patterns, n_k, n_sites)[source]

Stack flat per-bin FS patterns into (n_bins, n_k, n_sites) float32.

Empty bin_patterns yields shape (0, n_k, n_sites) (integrated-only).

Parameters:
Return type:

ndarray

Loader

I/O layer: load master-pattern .npz (raw FS + Lambert expand).

Lambert geometry and display scaling live in ebsdsim.lambert; this module owns NPZ I/O and the expand-to-Lambert orchestration.

Quick start

>>> from ebsdsim.io.load import load_master_pattern, to_uint8, save_png_gray
>>> mp = load_master_pattern("GaN-master-pattern.npz")  # raw Lambert data in mp.data
>>> disp, _ = mp.lambert_data(normalize="robust")  # display scaling on demand
>>> nh = disp[0, 0, 0]  # energy-integrated, site-integrated, north hemisphere
>>> save_png_gray(to_uint8(nh), "GaN_integrated_nh.png")
class ebsdsim.io.load.LoadedMasterPattern(meta, integrated_fs, bin_fs, kij, khat, pg_operators, fs_normals, bin_voltages_kv, bin_weights, site_weights=None, data=<factory>, axes=<factory>, _maps=<factory>)[source]

Bases: object

Master pattern loaded from a .npz file.

meta holds simulation metadata. integrated_fs and bin_fs are fundamental-sector intensities; data is the expanded Lambert tensor of raw values. See axes for index maps.

n_bins == 0 (empty bin_fs) means energy-integrated only: voltages and weights describe the energy model but no per-bin intensity slices were stored. Current solvers (lu_smith and Smith) store one pattern per voltage bin; bin_voltages_kv.size must not be treated as n_bins for older integrated-only files.

Parameters:
  • meta (dict[str, Any])

  • integrated_fs (NDArray[float32])

  • bin_fs (NDArray[float32])

  • kij (NDArray[int32])

  • khat (NDArray[float32])

  • pg_operators (NDArray[float64])

  • fs_normals (NDArray[float64])

  • bin_voltages_kv (NDArray[float32])

  • bin_weights (NDArray[float32])

  • site_weights (NDArray[float32] | None)

  • data (NDArray[float32])

  • axes (dict[str, Any])

  • _maps (dict[bool, tuple[NDArray[float32], NDArray[float32], NDArray[uint8]]])

meta: dict[str, Any]
integrated_fs: NDArray[float32]
bin_fs: NDArray[float32]
kij: NDArray[int32]
khat: NDArray[float32]
pg_operators: NDArray[float64]
fs_normals: NDArray[float64]
bin_voltages_kv: NDArray[float32]
bin_weights: NDArray[float32]
site_weights: NDArray[float32] | None = None
data: NDArray[float32]
axes: dict[str, Any]
property halfw: int
property side: int
property n_k: int
property n_sites: int
property n_bins: int

Number of stored per-bin intensity slices (0 = integrated-only).

property is_centrosymmetric: bool
property needs_southern_hemisphere: bool
reduce_over_sites(values_fs)[source]

Collapse a (n_k, n_sites) array to one value per direction.

Parameters:

values_fs (NDArray[floating])

Return type:

NDArray[float32]

lambert_data(*, normalize=None, robust_p_low=0.01, robust_p_high=0.99)[source]

Expand raw FS intensities to Lambert (E, S, H, side, side).

normalize is None (raw), "minmax", or "robust". Display scaling is applied on demand only; data always stays raw.

Parameters:
  • normalize (Literal['minmax', 'robust'] | None)

  • robust_p_low (float)

  • robust_p_high (float)

Return type:

tuple[NDArray[float32], dict[str, Any]]

reconstruct(values_fs=None, *, normalize=None, robust_p_low=0.01, robust_p_high=0.99, interp='bilinear')[source]

Expand fundamental-sector values into full (side, side) hemispheres.

Returns (nh, sh). For centrosymmetric groups sh is a copy of nh. If values_fs is None the integrated pattern is used.

Parameters:
  • values_fs (NDArray[floating] | None)

  • normalize (Literal['minmax', 'robust'] | None)

  • robust_p_low (float)

  • robust_p_high (float)

  • interp (Literal['nearest', 'bilinear'])

Return type:

tuple[NDArray[float32], NDArray[float32]]

reconstruct_integrated(**kwargs)[source]

Expand the energy-integrated master pattern.

Parameters:

kwargs (Any)

Return type:

tuple[NDArray[float32], NDArray[float32]]

reconstruct_bin(bin_index, **kwargs)[source]

Expand a single per-energy-bin intermediate.

Raises IndexError when no per-bin slices were stored (n_bins == 0, integrated-only).

Parameters:
  • bin_index (int)

  • kwargs (Any)

Return type:

tuple[NDArray[float32], NDArray[float32]]

__init__(meta, integrated_fs, bin_fs, kij, khat, pg_operators, fs_normals, bin_voltages_kv, bin_weights, site_weights=None, data=<factory>, axes=<factory>, _maps=<factory>)
Parameters:
  • meta (dict[str, Any])

  • integrated_fs (NDArray[float32])

  • bin_fs (NDArray[float32])

  • kij (NDArray[int32])

  • khat (NDArray[float32])

  • pg_operators (NDArray[float64])

  • fs_normals (NDArray[float64])

  • bin_voltages_kv (NDArray[float32])

  • bin_weights (NDArray[float32])

  • site_weights (NDArray[float32] | None)

  • data (NDArray[float32])

  • axes (dict[str, Any])

  • _maps (dict[bool, tuple[NDArray[float32], NDArray[float32], NDArray[uint8]]])

Return type:

None

ebsdsim.io.load.load_master_pattern(path)[source]

Load an ebsdsim master-pattern .npz.

Parameters:

path (str or Path) – File written by ebsdsim.save_master_pattern().

Returns:

Raw Lambert data in LoadedMasterPattern.data; call LoadedMasterPattern.lambert_data() for display scaling. n_bins is the number of stored intensity slices (0 when the file is integrated-only); do not equate it with bin_voltages_kv.size.

Return type:

LoadedMasterPattern

Notes

Folding geometry is taken from the stored pg_operators / fs_normals arrays (and the oriented meta['pg_symbol'] when present). The loader never recomputes operators from a bare pg_num, which would be orientation-ambiguous for some crystal families.

ebsdsim.io.load.build_master_pattern_data(*, integrated_fs, bin_fs, kij, pg_operators, fs_normals, hw, side, needs_southern_hemisphere, site_weights=None, normalize=None, robust_p_low=0.01, robust_p_high=0.99, interp='bilinear')[source]

Expand the fundamental sector into a dense (E, S, H, side, side) tensor.

Axes

E (energy): 1 + n_bins when n_bins > 1 (index 0 is the

energy-integrated pattern, index 1 + b is bin b); otherwise 1 (integrated-only when n_bins == 0, or a single stored bin that shares index 0 when n_bins == 1).

S (site): 1 + n_sites when n_sites > 1 (index 0 is the

site-integrated pattern, index 1 + s is site s); otherwise 1 (the single site).

H (hemisphere): 2 when needs_southern_hemisphere else 1

(index 0 north, index 1 south).

The point-group pixel-source map is built once per hemisphere and shared across every energy/site channel, so the fundamental sector is expanded without redundant per-channel geometry work.

Returns (data, axes) where axes documents the index layout.

Parameters:
Return type:

tuple[NDArray[float32], dict[str, Any]]

ebsdsim.io.load.to_uint8(img01)[source]

Convert a float image in [0, 1] to uint8 [0, 255].

Parameters:

img01 (NDArray[floating])

Return type:

NDArray[uint8]

ebsdsim.io.load.save_png_gray(img_uint8, path)[source]

Write a 2-D uint8 array as an 8-bit grayscale PNG (stdlib only).

Parameters:
  • img_uint8 (NDArray[uint8])

  • path (str | Path)

Return type:

Path

Display scaling

Lambert layer: display normalization (minmax / robust percentiles).

ebsdsim.lambert.display.scale_fs_channel(vals, normalize, *, robust_p_low=0.01, robust_p_high=0.99)[source]

Scale one fundamental-sector channel to [0, 1] for display.

Parameters:
  • normalize (Literal['minmax', 'robust'] | None) – None — return raw values (no scaling). "minmax" — divide by per-channel min/max (lossless up to float precision). "robust" — IQR outlier gate, then percentile window (lossy by default uses robust_p_low / robust_p_high).

  • robust_p_low (float) – Percentiles in [0, 1] used only when normalize="robust".

  • robust_p_high (float) – Percentiles in [0, 1] used only when normalize="robust".

  • vals (NDArray[floating])

Return type:

NDArray[float32]