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.3.tar.gz (772.2 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.3-py3-none-any.whl (362.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ebsdsim-0.1.3.tar.gz
  • Upload date:
  • Size: 772.2 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.3.tar.gz
Algorithm Hash digest
SHA256 6958b77d133a47cb22f21a7c038f3641615677d74008d971a9be17f7b3abeb48
MD5 1f313e00eae60a6304b368099cb8b6c7
BLAKE2b-256 5290bb3817aae564702ff43048e412b7ba554969c0c77a0503fed98951df0ba0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ebsdsim-0.1.3.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.3-py3-none-any.whl.

File metadata

  • Download URL: ebsdsim-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 362.3 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d67fdd5c677a1b87c49fffff986bf18ee2c146066810bb036894772c593310c3
MD5 3edbb959ed5a3395a2a7a1aac0ae0f1f
BLAKE2b-256 ceb60c659c97e5937e22a993c6661d556d00a516e899fb8139c8716907359279

See more details on using hashes here.

Provenance

The following attestation bundles were made for ebsdsim-0.1.3-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