Skip to main content

Crystallographic stress-strain analysis with Voigt-Mandel notation and mechanical equilibrium constraints

Project description

midas-stress

Crystallographic stress-strain analysis with Voigt-Mandel notation and mechanical equilibrium constraints.

A pure-Python library (NumPy + SciPy) for computing stress from strain in polycrystalline materials measured by High-Energy Diffraction Microscopy (HEDM), neutron diffraction, synchrotron strain scanning, or EBSD. Optional PyTorch backend for differentiable analysis.

Part of the MIDAS toolkit.

Installation

pip install midas-stress

For the PyTorch backend (GPU-accelerated, differentiable):

pip install midas-stress[torch]

Quick start — with any HEDM code

The library works with numpy arrays from any source — MIDAS, hexrd, ImageD11, DAXM, or your own scripts. Just provide orientations, strains, and volumes:

import numpy as np
import midas_stress as ms

# Your data (from hexrd, ImageD11, or any source):
orientations = np.array(...)   # (N, 3, 3) orientation matrices
strains = np.array(...)        # (N, 3, 3) strain tensors (lab frame)
volumes = np.array(...)        # (N,) grain volumes

# One function does everything:
result = ms.compute_stress(
    strain=strains,
    stiffness=ms.get_stiffness("Cu"),
    orient=orientations,
    volumes=volumes,
)

print(f"Mean von Mises: {result['von_mises'].mean():.1f} GPa")
print(f"d0 correction:  {result['hydrostatic_shift']:.1f} GPa")
print(f"Correction SE:  {result['uncertainty']['hydrostatic_se_MPa']:.1f} MPa")

The returned result dict contains:

  • stress_raw — per-grain stress before equilibrium correction
  • stress_corrected — per-grain stress after correction
  • hydrostatic_corrected, deviatoric, von_mises — decomposition
  • hydrostatic_shift — the d0 correction that was applied
  • uncertainty — statistical uncertainty of the correction

Quick start — with MIDAS output

import midas_stress as ms

grains = ms.read_grains("Grains.csv")

# Optional: convert MIDAS -> APS frame
sam = ms.grains_midas_to_sample(
    grains['orientations'], grains['positions'],
    grains['strain_fable'], target_frame="aps",
)

result = ms.compute_stress(
    strain=sam['strains'],
    stiffness=ms.get_stiffness("Cu"),
    orient=sam['orientations'],
    volumes=(4/3) * 3.14159 * grains['radii']**3,
    confidences=grains.get('confidences'),
    min_confidence=0.5,
)

Why equilibrium constraints matter

Every HEDM experiment has an unknown strain-free lattice parameter (d0). A tiny error in d0 causes a large systematic error in hydrostatic stress — identical for every grain and therefore invisible in grain-to-grain comparisons:

Material d0 error (ppm) Hydrostatic stress error (MPa)
Cu 100 41
Fe 100 50
Ni 100 54
W 100 93

midas-stress is the only library that fixes this via mechanical equilibrium:

  • FF-1: Volume-average stress constraint (forces macroscopic balance)
  • FF-2: Force-balance d0 (determines hydrostatic component from equilibrium, not from d0)
  • Confidence weighting: handles incomplete grain populations
  • Uncertainty estimation: reports how reliable the correction is

Features

Voigt-Mandel tensor algebra

voigt = ms.tensor_to_voigt(strain_3x3)     # (3,3) -> (6,)
tensor = ms.voigt_to_tensor(voigt_6)        # (6,) -> (3,3)
M = ms.rotation_voigt_mandel(orient)        # 6x6 rotation in Voigt space
p = ms.hydrostatic(stress)                  # scalar pressure
s = ms.deviatoric(stress)                   # deviatoric tensor
vm = ms.von_mises(stress)                   # von Mises equivalent

All operations are vectorized: pass (N, 3, 3) arrays for batch computation.

Hooke's law with stiffness database

# Built-in stiffness for 9 materials: Au, Cu, Al, Fe, Ni, Ti, W, Si, CeO2
C = ms.get_stiffness("Fe")

# Or build your own
C = ms.cubic_stiffness(C11=231.4, C12=134.7, C44=116.4)
C = ms.hexagonal_stiffness(C11=162.4, C12=92.0, C13=69.0, C33=180.7, C44=46.7)

# d0 sensitivity analysis
sens = ms.d0_sensitivity("Cu")
print(f"Cu: {sens['sensitivity_MPa_per_100ppm']:.1f} MPa per 100 ppm d0 error")

Coordinate frame conversions

# MIDAS (X=beam, Y=OB, Z=up) <-> APS (X=OB, Y=up, Z=beam)
sam = ms.grains_midas_to_sample(orientations, positions, strains,
                                 target_frame="aps", omega_deg=0)

Orientation and misorientation

angle, axis = ms.misorientation(euler1, euler2, space_group=225)
# All 230 space groups supported
# C-accelerated when MIDAS is built; pure-Python fallback otherwise

I/O

grains = ms.read_grains("Grains.csv")      # MIDAS CSV format
grains = ms.read_grains("output.h5")       # Consolidated HDF5

PyTorch backend (optional)

import midas_stress.torch_backend as mst
stress = mst.hooke_stress(strain_tensor, stiffness, orient, frame="lab")

Voigt-Mandel convention

v = [T_xx, T_yy, T_zz, sqrt(2)*T_xy, sqrt(2)*T_xz, sqrt(2)*T_yz]

The sqrt(2) scaling preserves the Frobenius norm: ||T||_F == ||v||_2.

Citation

@article{midas_stress,
  title   = {Determination of the strain-free lattice parameter from
        mechanical equilibrium in grain-resolved diffraction stress analysis},
  author  = {Sharma, Hemant and Park, Jun-Sang and Kenesei, Peter},
  journal = {submitted},
  year    = {2026},
}

License

BSD-3-Clause. See LICENSE.

For maintainers

See RELEASING.md for the release workflow (./release.sh <version> --publish handles everything end-to-end).

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_stress-0.1.6.tar.gz (36.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_stress-0.1.6-py3-none-any.whl (28.0 kB view details)

Uploaded Python 3

File details

Details for the file midas_stress-0.1.6.tar.gz.

File metadata

  • Download URL: midas_stress-0.1.6.tar.gz
  • Upload date:
  • Size: 36.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for midas_stress-0.1.6.tar.gz
Algorithm Hash digest
SHA256 5a0a770b618f3cf7a2fade79600d2bb30ddf09247ea964dd5fa4ddbab9ac4872
MD5 445fc8157cf040d8511beaced8165852
BLAKE2b-256 b4d51101bbf9a7ed97edbd34ca9199ba579fbc46e3cafd8aa8c75eb0bcc62101

See more details on using hashes here.

File details

Details for the file midas_stress-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: midas_stress-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 28.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for midas_stress-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 29ee51ca30b320592f5c9a0782a4c771ea23e7797002f45bebe244e315b55889
MD5 2c23bfab6c7f86a32a1ea6659a486196
BLAKE2b-256 f284e62082366daeb9ac8df1f855edbe29759b51d7d214d5c5582663b682ab22

See more details on using hashes here.

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