Skip to main content

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.

Metadata

Release files for midas-uq 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for midas-uq 0.1.3
File Size Uploaded
midas_uq-0.1.3.tar.gz 38.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for midas-uq 0.1.3
File Interpreter ABI Platform
midas_uq-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 74.6 kB

Release files / midas_uq-0.1.3.tar.gz

Download URL midas_uq-0.1.3.tar.gz
Size 38.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4c93e420a2ec681539c5f68ea6f644f9e0638a7963fcb629e74a84545248a686
BLAKE2b-256 checksum
How to use checksums
30d93f1c96e46a6831dc66ab98d72c01d8314470024bad0b65b87bd417043d48
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.

Transparency log

Release files / midas_uq-0.1.3-py3-none-any.whl

Download URL midas_uq-0.1.3-py3-none-any.whl
Size 35.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d12f2cf1370ce49a0a307f697857b1c8e02cca23a56fd7be0602f573ce38c9f6
BLAKE2b-256 checksum
How to use checksums
5919878a021c4707640498d2236101da0465eb694f9d3d50353ba3ac9a20b234
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page