Skip to main content

Cross-validation based uncertainty quantification for HEDM grain refinement (FF, NF, pf)

Project description

midas-uq

Cross-validation based uncertainty quantification for High-Energy Diffraction Microscopy (HEDM) grain refinement. Three diagnostics, three modalities (far-field, point-focused, near-field), all built on the end-to-end differentiable forward model of midas-diffract.

Companion paper: H. Sharma, J.-S. Park, P. Kenesei, N. Andrejevic & M. Cherukara, Cross-Validation Based Uncertainty Quantification for HEDM Grain Refinement, IUCrJ (in preparation, 2026).

What it does

For each grain in a polycrystal HEDM refinement, midas-uq answers:

  • How reproducible is this grain's refined state under random resampling of its measured spots (or omega frames)?half_half
  • Which individual measurements are driving the fit, and which (if any) appear corrupted?jackknife
  • What is the local Gaussian-posterior covariance from the inverse Hessian?laplace_covariance
  • Is refinement overfitting in the low-spots-per-DOF regime?rfree_gap

No ground truth required. Half-half disagreement and jackknife influence are post-hoc and label-free. The differentiable forward model from paper I makes population-scale resampling (hundreds of grains × tens of splits) a single-CPU minute, not a day.

Installation

pip install midas-uq         # adds midas-diffract automatically

Optional CPU multi-processing for population studies:

pip install "midas-uq[mp]"

Notebooks

Worked-example Jupyter notebooks live in notebooks/. They are not shipped with pip install — get them by cloning the MIDAS repository.

Quick start (Python)

import torch
import midas_uq as muq
import midas_diffract as md

# Build the forward model the usual way (see midas-diffract docs)
geom  = md.HEDMGeometry(...)
model = md.HEDMForwardModel(hkls=..., thetas=..., geometry=geom)

# Grain seed (e.g., from a Grains.csv row)
init = muq.GrainState(
    euler_rad=torch.tensor([phi1, Phi, phi2], dtype=torch.float64),
    latc=torch.tensor([a, b, c, alpha, beta, gamma], dtype=torch.float64),
    pos=torch.tensor([x, y, z], dtype=torch.float64),
)

# Observed spots: (N, 3) of (2theta, eta, omega) in radians
obs = ...

# 1. Half-half UQ
uq = muq.half_half(model, init, obs, mode="ff", n_splits=5)
print(uq.misori_median_deg, uq.lattice_median_A)

# 2. Per-spot jackknife (only on a flagged grain)
jk = muq.jackknife(model, init, obs, mode="ff")
print(jk.top_k(10))  # 10 most influential spots

# 3. Laplace baseline for comparison
sigma_vec = torch.tensor([sigma_2theta, sigma_eta, sigma_omega],
                         dtype=torch.float64)
lp = muq.laplace_covariance(model, init, obs, sigma_vec, refine_first=True)
print(lp.misori_p95_deg, lp.condition_number)

For NF-HEDM, observations is a (F, H, W) detector volume and the API is the same with mode="nf"; see examples/nf_frame_split.py.

Quick start (CLI)

For a standard MIDAS dataset (Grains.csv + SpotMatrix.csv + paramstest + hkls.csv):

# Population half-half UQ (writes one row per grain)
midas-uq half-half \
    --params  /path/to/paramstest.txt \
    --hkls    /path/to/hkls.csv \
    --grains  /path/to/Grains.csv \
    --spot-matrix /path/to/SpotMatrix.csv \
    --n-splits 5 \
    --out uq_half_half.csv

# Drill into a single grain
midas-uq jackknife --grain-id 5823 ...
midas-uq laplace   --grain-id 5823 ...

API surface

Symbol Modality Description
half_half(model, init, obs, mode='ff'|'pf'|'nf', ...) all K-split UQ dispatch
jackknife(model, init, obs, mode=...) all Leave-one-out dispatch
half_half_spots, jackknife_spots FF/pf Spot-based
half_half_frames, jackknife_frames NF Frame-based
laplace_covariance FF/pf Hessian baseline
rfree_gap FF/pf Train/holdout loss tracking
GrainState - Grain (euler, latc, pos) container

Result dataclasses: HalfHalfResult, JackknifeResult, LaplaceResult, RFreeResult.

When to use what

Diagnostic Cost per grain Surfaces
rfree_gap 1× refine overfitting at low n_obs/DOF (sparse / mosaic / pf-HEDM)
half_half (K=5) 10× refine noise + model misspec + local-minimum basin
jackknife N_obs × refine per-spot leverage and corruption candidates
laplace_covariance 1× Hessian local Gaussian-posterior baseline

Half-half is the recommended population-scale diagnostic; jackknife is the drill-down on grains flagged by half-half; Laplace gives a complementary Gaussian baseline whose discrepancy from the empirical half-half spread itself diagnoses non-Gaussian posterior structure.

Reproducing the companion paper

The Ti-7Al population study, Park22 in-situ tensile sweep, synthetic sweeps, and figure scripts live in dev/paper/ of the repository.

License

BSD-3-Clause.

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

midas_uq-0.1.0.tar.gz (31.5 kB view details)

Uploaded Source

Built Distribution

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

midas_uq-0.1.0-py3-none-any.whl (33.1 kB view details)

Uploaded Python 3

File details

Details for the file midas_uq-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for midas_uq-0.1.0.tar.gz
Algorithm Hash digest
SHA256 caed238855c359272090d38ba372395cc933fb8454985cc965875eeea6aaa74f
MD5 01d109c92c71b891d9ffec7bcfc25571
BLAKE2b-256 fe31a6c51b0510786b2bc5816df96bd9aab2cae5de4f5662990ab3a4edf6171d

See more details on using hashes here.

Provenance

The following attestation bundles were made for midas_uq-0.1.0.tar.gz:

Publisher: python-packages.yml on marinerhemant/MIDAS

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

File details

Details for the file midas_uq-0.1.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for midas_uq-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 30075e0645c325897ed2f3f203cc7d10ad3b49e066fe92c9a8e8ecf9f7e23c03
MD5 311c43f964955cac2f754791951209cc
BLAKE2b-256 264dc838d31e7daf3414a0fd03da4cd0163a451ea3f097855dc828cf1bf84eb1

See more details on using hashes here.

Provenance

The following attestation bundles were made for midas_uq-0.1.0-py3-none-any.whl:

Publisher: python-packages.yml on marinerhemant/MIDAS

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