Skip to main content

GPU-accelerated dynamical EBSD master-pattern simulation.

Project description

ebsdsim — dynamical EBSD master patterns

ebsdsim

CI Python License: MIT

Dynamical EBSD master-pattern simulation for Python.

ebsdsim computes Lambert-projected Kikuchi master patterns from a crystal structure using multi-beam dynamical electron diffraction (Bloch formulation). Beams are classified with Bethe perturbation theory (bethe_c_* cutoffs); the pattern is shaped equally by the beam and Monte Carlo model (energy, tilt, depth / energy distribution) and by those dynamical settings (Bethe cutoffs, rank, dmin).

The default Lambert raster uses halfw=250, i.e. 501×501 pixels (side = 1 + 2 × halfw, always odd).


Features

  • Dynamical diffraction — Bloch-theory multi-beam solve with fixed-rank Smith / Lyapunov iteration; Bethe theory selects which reflections enter the system.
  • Experiment-aware weighting — Monte Carlo depth / energy distributions (fast surrogate by default, or full GPU Monte Carlo) keyed to beam voltage and specimen tilt.
  • Automatic stopping — energy-bin integration and MC both stop when their outputs stop changing.
  • Portable output — compressed .npz files with symmetry-reduced fundamental-sector data; expand to full Lambert hemispheres with NumPy only via mploader.

What drives the pattern?

Input family Examples Typical use
Beam & specimen voltage_kv, sigma_deg, omega_deg, energy_binwidth_keV Match microscope settings and sample tilt — usually the first knobs to tune against experiment.
Monte Carlo mc_backend, mc_auto_stop, mc_relative_tol, n_trajectories Control how depth and energy loss are sampled (or approximated by the surrogate).
Dynamical diffraction bethe_c_strong, bethe_c_weak, bethe_c_cutoff, dbdiff_sg_cutoff, rank, dmin Bethe beam selection and multi-beam solve settings.
Raster halfw Lambert half-width; output size is (1 + 2×halfw)².
Structure lattice, sites, b_iso Crystal geometry and thermal motion (structure factors).

All of the above are keyword arguments to master_pattern and master_pattern_from_cif.


Debye–Waller factor

Per-site isotropic Debye–Waller factors are often unknown when only a lattice and composition are available. When b_iso is omitted on an Atom, or when a CIF lacks _atom_site_B_iso_or_equiv / _atom_site_U_iso_or_equiv, ebsdsim defaults to 0.5 Ų (stored internally as 0.005 nm²) — a room-temperature isotropic fallback.

Override per site when you have better data:

es.Atom("Ga", x=1/3, y=2/3, z=0.0, b_iso=0.45)  # Ų

In the future, defaults should come from the CIF when present (e.g. values refined against neutron diffraction), from DFT, or from modern surrogates that predict site-resolved thermal parameters reliably. Until then, treat the default as a placeholder and set b_iso explicitly when it matters for your comparison.


Requirements

Python 3.10 – 3.13
Runtime deps NumPy, wgpu ≥ 0.29
GPU WebGPU-capable adapter (see platforms below)

Supported platforms

OS Backend Notes
macOS Metal
Windows Vulkan or DirectX 12 Requires recent GPU drivers.
Linux Vulkan Install Mesa/Vulkan drivers for your GPU.

Simulation requires a working WebGPU adapter. Headless servers without GPU passthrough will not be able to run master_pattern*.


Install

pip install ebsdsim

From source (editable), with dev and notebook extras:

git clone https://github.com/ZacharyVarley/ebsdsim.git
cd ebsdsim
pip install -e ".[dev,docs]"

Quick start

import ebsdsim as es

mp = es.master_pattern_from_cif(
    "GaN.cif",                # bundled preset, or any path to a .cif file
    halfw=250,                # Lambert half-width → 501×501 output
    voltage_kv=20.0,
    sigma_deg=70.0,           # specimen tilt (degrees)
    omega_deg=0.0,            # azimuthal sample rotation (degrees)
    energy_binwidth_keV=1.0,
    mc_backend="surrogate",   # or "gpu"
    bethe_c_strong=20.0,
    bethe_c_weak=40.0,
    bethe_c_cutoff=200.0,
    dbdiff_sg_cutoff=1.0,
    rank=20,
    dmin=0.05,                # nm
)

print(mp.pattern.shape)       # (501, 501)
mp.save("GaN-master-pattern.npz")

Bundled presets: "GaN.cif", "Ni.cif" (also accepts a full filesystem path).

Manual lattice + sites (lengths in Å). Omit b_iso to use the 0.5 Ų default:

ni = es.Material(
    cell=es.Cell(a=3.52, b=3.52, c=3.52, space_group="Fm-3m"),
    atoms=[es.Atom("Ni", x=0.0, y=0.0, z=0.0)],
    name="Ni",
)
mp = es.master_pattern(ni, voltage_kv=20.0, sigma_deg=70.0, halfw=250)

Beam & Monte Carlo parameters

These set the incident beam and how electrons lose energy and penetrate the sample before diffraction. They are passed directly to master_pattern*:

Parameter Default Role
voltage_kv 20.0 Nominal beam energy (kV)
sigma_deg 70.0 Specimen tilt angle (degrees) fed to the MC / surrogate model
omega_deg 0.0 Azimuthal sample rotation (degrees); used by GPU MC
energy_binwidth_keV 1.0 Width of energy-loss bins integrated into the master pattern
relative_image_stop 0.01 Stop adding bins when Δimage/image falls below this
marginal_coverage 1.0 Fraction of MC energy bins to include (1.0 = all)
mc_backend "surrogate" "gpu" for full boundary Monte Carlo
mc_auto_stop True GPU MC: stop when depth/energy fits converge
mc_relative_tol 0.01 GPU MC convergence tolerance
n_trajectories 1048576 GPU MC trajectory budget when mc_auto_stop=False

GPU Monte Carlo example:

mp = es.master_pattern_from_cif(
    "GaN.cif",
    voltage_kv=20.0,
    sigma_deg=70.0,
    omega_deg=0.0,
    mc_backend="gpu",
    mc_auto_stop=True,
    mc_relative_tol=0.01,
)
print(mp.metadata["mc_n_trajectories"], mp.metadata["mc_converged"])

Dynamical diffraction parameters

The solve always uses the Bloch formulation. Bethe perturbation theory ranks reflections and decides which beams are strong, weak, or excluded (bethe_c_*). Those cutoffs usually matter more than fine-tuning dmin or rank when matching reference patterns:

Parameter Default Role
bethe_c_strong 20.0 Excitation-score threshold for strong beams
bethe_c_weak 40.0 Threshold band for weak beams
bethe_c_cutoff 200.0 Upper cutoff — beams above this are excluded
dbdiff_sg_cutoff 1.0 Structure-factor difference cutoff for beam coupling
rank 20 Truncation rank for the fixed-rank Lyapunov (Smith) solve
dmin 0.05 nm Minimum d-spacing — sets the reflection sphere (smaller → more beams, slower)
halfw 250 Lambert half-width; pattern size is (1 + 2×halfw) × (1 + 2×halfw)

mp.pattern, mp.data, and mp.integrated are always raw dynamical intensities. For display scaling, call mp.lambert_data(normalize="minmax") or mp.lambert_data(normalize="robust", robust_p_low=0.01, robust_p_high=0.99). Scaling is never baked into the simulation result.


Loading a saved pattern (NumPy only)

ebsdsim/mploader.py is self-contained (NumPy only). Copy it into any project that only needs to read .npz output.

from ebsdsim.mploader import load_master_pattern, to_uint8, save_png_gray

mp = load_master_pattern("GaN-master-pattern.npz")
disp, _ = mp.lambert_data(normalize="minmax")

nh = disp[0, 0, 0]   # energy-integrated, site-integrated, north hemisphere
save_png_gray(to_uint8(nh), "GaN_integrated_nh.png")

.npz layout (summary)

Array Meaning
fundamental_sector Raw symmetry-reduced intensities (E, S, n_k)
fundamental_kij, fundamental_khat Lambert indices and unit directions per FS pixel
pg_operators, fs_normals Point-group matrices and sector bounding normals
bin_voltages_kv, bin_weights Per-bin beam voltage and energy weight
site_weights Normalized occupancy × multiplicity weights for the site marginal
meta_json UTF-8 JSON simulation metadata (includes beam, MC, and dynamical settings)

See examples/02_save_and_load.ipynb for a full walkthrough.


Examples

Resource Description
examples/01_quick_start.ipynb GaN and Ni patterns
examples/02_save_and_load.ipynb Save, reload, export PNGs
scripts/run_gan_example.py Full-resolution GaN script

Preset CIFs ship under ebsdsim/data/preset_cifs/ (Ni, GaN).


Development

pip install -e ".[dev,docs]"
pytest -m "not slow"          # CPU tests; GPU tests skip if no adapter
pytest -m slow                # end-to-end GPU runs (needs WebGPU)
python -m build               # sdist + wheel (requires `build` extra)

CI runs CPU tests on Ubuntu (Python 3.11–3.12) and full GPU tests on macOS (Metal). See .github/workflows/ci.yml.

Releasing (automated PyPI)

Releases are published by pushing a version tag. The .github/workflows/release.yml workflow builds the sdist/wheel, uploads them to the GitHub release, and publishes to PyPI via trusted publishing (no API token in the repo).

One-time setup

  1. On PyPI: add a pending publisher
    • PyPI project name: ebsdsim
    • Owner: ZacharyVarley, repository: ebsdsim
    • Workflow: release.yml, environment: pypi
  2. On GitHub: repo Settings → Environments → create environment pypi (no secrets required for trusted publishing).

Each release

  1. Bump __version__ in ebsdsim/_version.py and add notes to CHANGELOG.md.

  2. Commit and push to main.

  3. Tag and push (tag must match ebsdsim._version, without the v prefix):

    git tag v0.1.0
    git push origin v0.1.0
    
  4. Watch the Release workflow; the package appears on pypi.org/project/ebsdsim when it finishes.


Contributing

  1. Fork the repo and create a branch from main.
  2. pip install -e ".[dev]" and run pytest -m "not slow" before opening a PR.
  3. If your change touches GPU paths or save/load, also run pytest -m slow on a machine with WebGPU (macOS Metal works).
  4. Keep PRs focused; include a short note in CHANGELOG.md under Unreleased when user-visible behavior changes.

Bug reports and feature requests: GitHub Issues.


License

MIT — see LICENSE. Copyright (c) Zachary Varley.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ebsdsim-0.1.4.tar.gz (771.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ebsdsim-0.1.4-py3-none-any.whl (361.2 kB view details)

Uploaded Python 3

File details

Details for the file ebsdsim-0.1.4.tar.gz.

File metadata

  • Download URL: ebsdsim-0.1.4.tar.gz
  • Upload date:
  • Size: 771.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ebsdsim-0.1.4.tar.gz
Algorithm Hash digest
SHA256 3f45685285025bf2d59ed90c4871f54d894e1be07da33185fb9b9abb38161dc7
MD5 e156051e6adcaf61bf5098098a248751
BLAKE2b-256 651a78adc6076aa44ff1c2d02348109b34be0ab07674e278e833d83977fd03f0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ebsdsim-0.1.4.tar.gz:

Publisher: release.yml on ZacharyVarley/ebsdsim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ebsdsim-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: ebsdsim-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 361.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ebsdsim-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b67089510c76df3ca5521edd08d6a11f208dbe1f7eebf3cd79c0feaf30034815
MD5 28d2773dcb3eb72fcdda6fb25c3c751f
BLAKE2b-256 814fff654715500c4dbeb2f7f0faa283c3ffd42bc4721538cfe8d9808ed01f08

See more details on using hashes here.

Provenance

The following attestation bundles were made for ebsdsim-0.1.4-py3-none-any.whl:

Publisher: release.yml on ZacharyVarley/ebsdsim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page