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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
caed238855c359272090d38ba372395cc933fb8454985cc965875eeea6aaa74f
|
|
| MD5 |
01d109c92c71b891d9ffec7bcfc25571
|
|
| BLAKE2b-256 |
fe31a6c51b0510786b2bc5816df96bd9aab2cae5de4f5662990ab3a4edf6171d
|
Provenance
The following attestation bundles were made for midas_uq-0.1.0.tar.gz:
Publisher:
python-packages.yml on marinerhemant/MIDAS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
midas_uq-0.1.0.tar.gz -
Subject digest:
caed238855c359272090d38ba372395cc933fb8454985cc965875eeea6aaa74f - Sigstore transparency entry: 1633400805
- Sigstore integration time:
-
Permalink:
marinerhemant/MIDAS@0cc140e5cb19f141534b88d7c95d32e3195f6263 -
Branch / Tag:
refs/tags/midas-uq-v0.1.0 - Owner: https://github.com/marinerhemant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-packages.yml@0cc140e5cb19f141534b88d7c95d32e3195f6263 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30075e0645c325897ed2f3f203cc7d10ad3b49e066fe92c9a8e8ecf9f7e23c03
|
|
| MD5 |
311c43f964955cac2f754791951209cc
|
|
| BLAKE2b-256 |
264dc838d31e7daf3414a0fd03da4cd0163a451ea3f097855dc828cf1bf84eb1
|
Provenance
The following attestation bundles were made for midas_uq-0.1.0-py3-none-any.whl:
Publisher:
python-packages.yml on marinerhemant/MIDAS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
midas_uq-0.1.0-py3-none-any.whl -
Subject digest:
30075e0645c325897ed2f3f203cc7d10ad3b49e066fe92c9a8e8ecf9f7e23c03 - Sigstore transparency entry: 1633400817
- Sigstore integration time:
-
Permalink:
marinerhemant/MIDAS@0cc140e5cb19f141534b88d7c95d32e3195f6263 -
Branch / Tag:
refs/tags/midas-uq-v0.1.0 - Owner: https://github.com/marinerhemant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-packages.yml@0cc140e5cb19f141534b88d7c95d32e3195f6263 -
Trigger Event:
release
-
Statement type: