midas-stress 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: midas-stress
3
+ Version: 0.1.0
4
+ Summary: Crystallographic stress-strain analysis with Voigt-Mandel notation and mechanical equilibrium constraints
5
+ Author-email: Hemant Sharma <hsharma@anl.gov>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/marinerhemant/MIDAS
8
+ Project-URL: Documentation, https://github.com/marinerhemant/MIDAS
9
+ Project-URL: Issues, https://github.com/marinerhemant/MIDAS/issues
10
+ Keywords: crystallography,stress,strain,HEDM,Voigt,Mandel,Hooke,misorientation
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Physics
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: numpy>=1.22
18
+ Requires-Dist: scipy>=1.8
19
+ Provides-Extra: torch
20
+ Requires-Dist: torch>=2.0; extra == "torch"
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0; extra == "dev"
23
+ Requires-Dist: pytest-cov; extra == "dev"
24
+
25
+ # midas-stress
26
+
27
+ Crystallographic stress-strain analysis with Voigt-Mandel notation and mechanical equilibrium constraints.
28
+
29
+ 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.
30
+
31
+ Part of the [MIDAS](https://github.com/marinerhemant/MIDAS) toolkit.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install midas-stress
37
+ ```
38
+
39
+ For the PyTorch backend (GPU-accelerated, differentiable):
40
+
41
+ ```bash
42
+ pip install midas-stress[torch]
43
+ ```
44
+
45
+ ## Quick start — with any HEDM code
46
+
47
+ The library works with **numpy arrays from any source** — MIDAS, hexrd, ImageD11, DAXM, or your own scripts. Just provide orientations, strains, and volumes:
48
+
49
+ ```python
50
+ import numpy as np
51
+ import midas_stress as ms
52
+
53
+ # Your data (from hexrd, ImageD11, or any source):
54
+ orientations = np.array(...) # (N, 3, 3) orientation matrices
55
+ strains = np.array(...) # (N, 3, 3) strain tensors (lab frame)
56
+ volumes = np.array(...) # (N,) grain volumes
57
+
58
+ # One function does everything:
59
+ result = ms.compute_stress(
60
+ strain=strains,
61
+ stiffness=ms.get_stiffness("Cu"),
62
+ orient=orientations,
63
+ volumes=volumes,
64
+ )
65
+
66
+ print(f"Mean von Mises: {result['von_mises'].mean():.1f} GPa")
67
+ print(f"d0 correction: {result['hydrostatic_shift']:.1f} GPa")
68
+ print(f"Correction SE: {result['uncertainty']['hydrostatic_se_MPa']:.1f} MPa")
69
+ ```
70
+
71
+ The returned `result` dict contains:
72
+ - `stress_raw` — per-grain stress before equilibrium correction
73
+ - `stress_corrected` — per-grain stress after correction
74
+ - `hydrostatic_corrected`, `deviatoric`, `von_mises` — decomposition
75
+ - `hydrostatic_shift` — the d0 correction that was applied
76
+ - `uncertainty` — statistical uncertainty of the correction
77
+
78
+ ## Quick start — with MIDAS output
79
+
80
+ ```python
81
+ import midas_stress as ms
82
+
83
+ grains = ms.read_grains("Grains.csv")
84
+
85
+ # Optional: convert MIDAS -> APS frame
86
+ sam = ms.grains_midas_to_sample(
87
+ grains['orientations'], grains['positions'],
88
+ grains['strain_fable'], target_frame="aps",
89
+ )
90
+
91
+ result = ms.compute_stress(
92
+ strain=sam['strains'],
93
+ stiffness=ms.get_stiffness("Cu"),
94
+ orient=sam['orientations'],
95
+ volumes=(4/3) * 3.14159 * grains['radii']**3,
96
+ confidences=grains.get('confidences'),
97
+ min_confidence=0.5,
98
+ )
99
+ ```
100
+
101
+ ## Why equilibrium constraints matter
102
+
103
+ 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:
104
+
105
+ | Material | d0 error (ppm) | Hydrostatic stress error (MPa) |
106
+ |----------|---------------|-------------------------------|
107
+ | Cu | 100 | 41 |
108
+ | Fe | 100 | 50 |
109
+ | Ni | 100 | 54 |
110
+ | W | 100 | 93 |
111
+
112
+ `midas-stress` is the **only** library that fixes this via mechanical equilibrium:
113
+
114
+ - **FF-1**: Volume-average stress constraint (forces macroscopic balance)
115
+ - **FF-2**: Force-balance d0 (determines hydrostatic component from equilibrium, not from d0)
116
+ - **Confidence weighting**: handles incomplete grain populations
117
+ - **Uncertainty estimation**: reports how reliable the correction is
118
+
119
+ ## Features
120
+
121
+ ### Voigt-Mandel tensor algebra
122
+
123
+ ```python
124
+ voigt = ms.tensor_to_voigt(strain_3x3) # (3,3) -> (6,)
125
+ tensor = ms.voigt_to_tensor(voigt_6) # (6,) -> (3,3)
126
+ M = ms.rotation_voigt_mandel(orient) # 6x6 rotation in Voigt space
127
+ p = ms.hydrostatic(stress) # scalar pressure
128
+ s = ms.deviatoric(stress) # deviatoric tensor
129
+ vm = ms.von_mises(stress) # von Mises equivalent
130
+ ```
131
+
132
+ All operations are vectorized: pass `(N, 3, 3)` arrays for batch computation.
133
+
134
+ ### Hooke's law with stiffness database
135
+
136
+ ```python
137
+ # Built-in stiffness for 9 materials: Au, Cu, Al, Fe, Ni, Ti, W, Si, CeO2
138
+ C = ms.get_stiffness("Fe")
139
+
140
+ # Or build your own
141
+ C = ms.cubic_stiffness(C11=231.4, C12=134.7, C44=116.4)
142
+ C = ms.hexagonal_stiffness(C11=162.4, C12=92.0, C13=69.0, C33=180.7, C44=46.7)
143
+
144
+ # d0 sensitivity analysis
145
+ sens = ms.d0_sensitivity("Cu")
146
+ print(f"Cu: {sens['sensitivity_MPa_per_100ppm']:.1f} MPa per 100 ppm d0 error")
147
+ ```
148
+
149
+ ### Coordinate frame conversions
150
+
151
+ ```python
152
+ # MIDAS (X=beam, Y=OB, Z=up) <-> APS (X=OB, Y=up, Z=beam)
153
+ sam = ms.grains_midas_to_sample(orientations, positions, strains,
154
+ target_frame="aps", omega_deg=0)
155
+ ```
156
+
157
+ ### Orientation and misorientation
158
+
159
+ ```python
160
+ angle, axis = ms.misorientation(euler1, euler2, space_group=225)
161
+ # All 230 space groups supported
162
+ # C-accelerated when MIDAS is built; pure-Python fallback otherwise
163
+ ```
164
+
165
+ ### I/O
166
+
167
+ ```python
168
+ grains = ms.read_grains("Grains.csv") # MIDAS CSV format
169
+ grains = ms.read_grains("output.h5") # Consolidated HDF5
170
+ ```
171
+
172
+ ### PyTorch backend (optional)
173
+
174
+ ```python
175
+ import midas_stress.torch_backend as mst
176
+ stress = mst.hooke_stress(strain_tensor, stiffness, orient, frame="lab")
177
+ ```
178
+
179
+ ## Voigt-Mandel convention
180
+
181
+ ```
182
+ v = [T_xx, T_yy, T_zz, sqrt(2)*T_xy, sqrt(2)*T_xz, sqrt(2)*T_yz]
183
+ ```
184
+
185
+ The sqrt(2) scaling preserves the Frobenius norm: `||T||_F == ||v||_2`.
186
+
187
+ ## Citation
188
+
189
+ ```bibtex
190
+ @article{midas_stress,
191
+ title = {midas-stress: A Python Library for Crystallographic
192
+ Stress-Strain Analysis with Mechanical Equilibrium Constraints},
193
+ author = {Sharma, Hemant and Park, Jun-Sang and Kenesei, Peter},
194
+ journal = {Journal of Applied Crystallography},
195
+ year = {2026},
196
+ }
197
+ ```
198
+
199
+ ## License
200
+
201
+ BSD-3-Clause. See [LICENSE](../../LICENSE).
@@ -0,0 +1,177 @@
1
+ # midas-stress
2
+
3
+ Crystallographic stress-strain analysis with Voigt-Mandel notation and mechanical equilibrium constraints.
4
+
5
+ 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.
6
+
7
+ Part of the [MIDAS](https://github.com/marinerhemant/MIDAS) toolkit.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install midas-stress
13
+ ```
14
+
15
+ For the PyTorch backend (GPU-accelerated, differentiable):
16
+
17
+ ```bash
18
+ pip install midas-stress[torch]
19
+ ```
20
+
21
+ ## Quick start — with any HEDM code
22
+
23
+ The library works with **numpy arrays from any source** — MIDAS, hexrd, ImageD11, DAXM, or your own scripts. Just provide orientations, strains, and volumes:
24
+
25
+ ```python
26
+ import numpy as np
27
+ import midas_stress as ms
28
+
29
+ # Your data (from hexrd, ImageD11, or any source):
30
+ orientations = np.array(...) # (N, 3, 3) orientation matrices
31
+ strains = np.array(...) # (N, 3, 3) strain tensors (lab frame)
32
+ volumes = np.array(...) # (N,) grain volumes
33
+
34
+ # One function does everything:
35
+ result = ms.compute_stress(
36
+ strain=strains,
37
+ stiffness=ms.get_stiffness("Cu"),
38
+ orient=orientations,
39
+ volumes=volumes,
40
+ )
41
+
42
+ print(f"Mean von Mises: {result['von_mises'].mean():.1f} GPa")
43
+ print(f"d0 correction: {result['hydrostatic_shift']:.1f} GPa")
44
+ print(f"Correction SE: {result['uncertainty']['hydrostatic_se_MPa']:.1f} MPa")
45
+ ```
46
+
47
+ The returned `result` dict contains:
48
+ - `stress_raw` — per-grain stress before equilibrium correction
49
+ - `stress_corrected` — per-grain stress after correction
50
+ - `hydrostatic_corrected`, `deviatoric`, `von_mises` — decomposition
51
+ - `hydrostatic_shift` — the d0 correction that was applied
52
+ - `uncertainty` — statistical uncertainty of the correction
53
+
54
+ ## Quick start — with MIDAS output
55
+
56
+ ```python
57
+ import midas_stress as ms
58
+
59
+ grains = ms.read_grains("Grains.csv")
60
+
61
+ # Optional: convert MIDAS -> APS frame
62
+ sam = ms.grains_midas_to_sample(
63
+ grains['orientations'], grains['positions'],
64
+ grains['strain_fable'], target_frame="aps",
65
+ )
66
+
67
+ result = ms.compute_stress(
68
+ strain=sam['strains'],
69
+ stiffness=ms.get_stiffness("Cu"),
70
+ orient=sam['orientations'],
71
+ volumes=(4/3) * 3.14159 * grains['radii']**3,
72
+ confidences=grains.get('confidences'),
73
+ min_confidence=0.5,
74
+ )
75
+ ```
76
+
77
+ ## Why equilibrium constraints matter
78
+
79
+ 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:
80
+
81
+ | Material | d0 error (ppm) | Hydrostatic stress error (MPa) |
82
+ |----------|---------------|-------------------------------|
83
+ | Cu | 100 | 41 |
84
+ | Fe | 100 | 50 |
85
+ | Ni | 100 | 54 |
86
+ | W | 100 | 93 |
87
+
88
+ `midas-stress` is the **only** library that fixes this via mechanical equilibrium:
89
+
90
+ - **FF-1**: Volume-average stress constraint (forces macroscopic balance)
91
+ - **FF-2**: Force-balance d0 (determines hydrostatic component from equilibrium, not from d0)
92
+ - **Confidence weighting**: handles incomplete grain populations
93
+ - **Uncertainty estimation**: reports how reliable the correction is
94
+
95
+ ## Features
96
+
97
+ ### Voigt-Mandel tensor algebra
98
+
99
+ ```python
100
+ voigt = ms.tensor_to_voigt(strain_3x3) # (3,3) -> (6,)
101
+ tensor = ms.voigt_to_tensor(voigt_6) # (6,) -> (3,3)
102
+ M = ms.rotation_voigt_mandel(orient) # 6x6 rotation in Voigt space
103
+ p = ms.hydrostatic(stress) # scalar pressure
104
+ s = ms.deviatoric(stress) # deviatoric tensor
105
+ vm = ms.von_mises(stress) # von Mises equivalent
106
+ ```
107
+
108
+ All operations are vectorized: pass `(N, 3, 3)` arrays for batch computation.
109
+
110
+ ### Hooke's law with stiffness database
111
+
112
+ ```python
113
+ # Built-in stiffness for 9 materials: Au, Cu, Al, Fe, Ni, Ti, W, Si, CeO2
114
+ C = ms.get_stiffness("Fe")
115
+
116
+ # Or build your own
117
+ C = ms.cubic_stiffness(C11=231.4, C12=134.7, C44=116.4)
118
+ C = ms.hexagonal_stiffness(C11=162.4, C12=92.0, C13=69.0, C33=180.7, C44=46.7)
119
+
120
+ # d0 sensitivity analysis
121
+ sens = ms.d0_sensitivity("Cu")
122
+ print(f"Cu: {sens['sensitivity_MPa_per_100ppm']:.1f} MPa per 100 ppm d0 error")
123
+ ```
124
+
125
+ ### Coordinate frame conversions
126
+
127
+ ```python
128
+ # MIDAS (X=beam, Y=OB, Z=up) <-> APS (X=OB, Y=up, Z=beam)
129
+ sam = ms.grains_midas_to_sample(orientations, positions, strains,
130
+ target_frame="aps", omega_deg=0)
131
+ ```
132
+
133
+ ### Orientation and misorientation
134
+
135
+ ```python
136
+ angle, axis = ms.misorientation(euler1, euler2, space_group=225)
137
+ # All 230 space groups supported
138
+ # C-accelerated when MIDAS is built; pure-Python fallback otherwise
139
+ ```
140
+
141
+ ### I/O
142
+
143
+ ```python
144
+ grains = ms.read_grains("Grains.csv") # MIDAS CSV format
145
+ grains = ms.read_grains("output.h5") # Consolidated HDF5
146
+ ```
147
+
148
+ ### PyTorch backend (optional)
149
+
150
+ ```python
151
+ import midas_stress.torch_backend as mst
152
+ stress = mst.hooke_stress(strain_tensor, stiffness, orient, frame="lab")
153
+ ```
154
+
155
+ ## Voigt-Mandel convention
156
+
157
+ ```
158
+ v = [T_xx, T_yy, T_zz, sqrt(2)*T_xy, sqrt(2)*T_xz, sqrt(2)*T_yz]
159
+ ```
160
+
161
+ The sqrt(2) scaling preserves the Frobenius norm: `||T||_F == ||v||_2`.
162
+
163
+ ## Citation
164
+
165
+ ```bibtex
166
+ @article{midas_stress,
167
+ title = {midas-stress: A Python Library for Crystallographic
168
+ Stress-Strain Analysis with Mechanical Equilibrium Constraints},
169
+ author = {Sharma, Hemant and Park, Jun-Sang and Kenesei, Peter},
170
+ journal = {Journal of Applied Crystallography},
171
+ year = {2026},
172
+ }
173
+ ```
174
+
175
+ ## License
176
+
177
+ BSD-3-Clause. See [LICENSE](../../LICENSE).
@@ -0,0 +1,91 @@
1
+ """midas-stress: Crystallographic stress-strain analysis.
2
+
3
+ Provides Voigt-Mandel tensor conversions, Hooke's law with single-crystal
4
+ stiffness, orientation/misorientation math, and mechanical equilibrium
5
+ constraints for polycrystalline stress analysis.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+
10
+ # --- Tensor / Voigt ---
11
+ from .tensor import (
12
+ tensor_to_voigt,
13
+ voigt_to_tensor,
14
+ tensor_to_voigt_engineering,
15
+ lattice_params_to_A_matrix,
16
+ lattice_params_to_strain,
17
+ strain_grain_to_lab,
18
+ strain_lab_to_grain,
19
+ rotation_voigt_mandel,
20
+ hydrostatic,
21
+ deviatoric,
22
+ von_mises,
23
+ )
24
+
25
+ # --- Hooke's law ---
26
+ from .hooke import hooke_stress
27
+
28
+ # --- Materials ---
29
+ from .materials import (
30
+ cubic_stiffness,
31
+ hexagonal_stiffness,
32
+ get_stiffness,
33
+ list_materials,
34
+ STIFFNESS_LIBRARY,
35
+ d0_sensitivity,
36
+ d0_sensitivity_table,
37
+ )
38
+
39
+ # --- Equilibrium ---
40
+ from .equilibrium import (
41
+ volume_average_stress_constraint,
42
+ hydrostatic_deviatoric_decomposition,
43
+ hydrostatic_deviatoric_decomposition_weighted,
44
+ equilibrium_correction_uncertainty,
45
+ d0_correction_strain_level,
46
+ correct_d0,
47
+ recover_d0,
48
+ )
49
+
50
+ # --- Orientation / Misorientation ---
51
+ from .orientation import (
52
+ misorientation,
53
+ misorientation_om,
54
+ misorientation_om_batch,
55
+ misorientation_quat_batch,
56
+ euler_to_orient_mat,
57
+ euler_to_orient_mat_batch,
58
+ orient_mat_to_quat,
59
+ orient_mat_to_euler,
60
+ quaternion_product,
61
+ quat_to_orient_mat,
62
+ fundamental_zone,
63
+ make_symmetries,
64
+ axis_angle_to_orient_mat,
65
+ rodrigues_to_orient_mat,
66
+ )
67
+
68
+ # --- Frame conversions ---
69
+ from .frames import (
70
+ R_MIDAS_TO_APS,
71
+ R_APS_TO_MIDAS,
72
+ lab_to_sample_rotation,
73
+ vector_midas_to_aps,
74
+ vector_aps_to_midas,
75
+ orient_midas_to_aps,
76
+ orient_aps_to_midas,
77
+ tensor_midas_to_aps,
78
+ tensor_aps_to_midas,
79
+ tensor_lab_to_sample,
80
+ grains_midas_to_sample,
81
+ )
82
+
83
+ # --- High-level pipeline ---
84
+ from .pipeline import compute_stress
85
+
86
+ # --- I/O ---
87
+ from .io import (
88
+ read_grains,
89
+ read_grains_csv,
90
+ read_grains_h5,
91
+ )