elasticipy 2.9.0__tar.gz → 3.0.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.
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/paper.bib +4 -2
- {elasticipy-2.9.0/src/elasticipy.egg-info → elasticipy-3.0.0}/PKG-INFO +2 -1
- {elasticipy-2.9.0 → elasticipy-3.0.0}/README.md +1 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Plasticity.rst +34 -34
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_StiffnessTensor.rst +1 -1
- elasticipy-3.0.0/docs/source/Tutorials/Tutorial_StressStrain.rst +231 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_ThermalExpansion.rst +9 -5
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/index.rst +4 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/FourthOrderTensor.py +360 -44
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/Plasticity.py +105 -55
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/SecondOrderTensor.py +243 -54
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/StressStrainTensors.py +9 -5
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/ThermalExpansion.py +88 -17
- {elasticipy-2.9.0 → elasticipy-3.0.0/src/elasticipy.egg-info}/PKG-INFO +2 -1
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/test_StiffnessTensor.py +147 -9
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/test_StressStrainTensors.py +168 -16
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/test_ThermalExpansion.py +15 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/test_plasticity.py +32 -15
- elasticipy-2.9.0/docs/source/Tutorials/Tutorial_StressStrain.rst +0 -445
- {elasticipy-2.9.0 → elasticipy-3.0.0}/.github/workflows/Codecov.yml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/.github/workflows/JOSS build.yml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/.github/workflows/cloc.yml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/.github/workflows/python-publish.yml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/.readthedocs.yaml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/CODE_OF_CONDUCT.md +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/CONTRIBUTING.md +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Elasticipy_vs_pymatgen.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Elate_vs_Elasticipy.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Example_Stiffness_tensor.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Example_StressStrain_arrays.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Example_WaveVelocity.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/MaterialsProject.json +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/Multiple_phases.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/essai_plasticity.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/Examples/example_readwrite.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/ElasticipyVSpymatgen.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/Nye.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/Plot_E.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/YoungModulus.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/JOSS/paper.md +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/LICENSE +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/_static/images/HyperSphericalCoordinates.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/index.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.FourthOrderTensor.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.Plasticity.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.SecondOrderTensor.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.SphericalFunction.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.StressStrainTensors.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Elasticipy.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/GUI.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_AveragingMethods.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_MultiplePhases.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_ReadWriteFiles.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/Tutorial_wave-velocities.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/Cyclic.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/E_PF.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/E_VRH_sections.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/E_hill_fiber.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/E_plot3D.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/E_xyz_sections.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/GUI.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/G_plot3D.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/G_plot3D_min.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/G_xyz_sections.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/Incremental.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/Shear.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/Stress-controlled.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/StressStrain-controlled.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/WaveVelocities.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials/images/plot_volumeFraction.png +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/Tutorials.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/conf.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/docs/source/modules.rst +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/pyproject.toml +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/requirements.txt +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/setup.cfg +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/CrystalSymmetries.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/PoleFigure.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/SphericalFunction.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/__init__.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/Elasticipy/gui.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/elasticipy.egg-info/SOURCES.txt +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/elasticipy.egg-info/dependency_links.txt +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/elasticipy.egg-info/requires.txt +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/src/elasticipy.egg-info/top_level.txt +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/MaterialsProject.json +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/__init__.py +0 -0
- {elasticipy-2.9.0 → elasticipy-3.0.0}/tests/test_SphericalFunction.py +0 -0
|
@@ -6,6 +6,7 @@ pages = {314-319},
|
|
|
6
6
|
year = {2013},
|
|
7
7
|
issn = {0927-0256},
|
|
8
8
|
url = {https://doi.org/10.1016/j.commatsci.2012.10.028},
|
|
9
|
+
doi = {10.1016/j.commatsci.2012.10.028},
|
|
9
10
|
author = {Shyue Ping Ong and William Davidson Richards and Anubhav Jain and Geoffroy Hautier and Michael Kocher and Shreyas Cholia and Dan Gunter and Vincent L. Chevrier and Kristin A. Persson and Gerbrand Ceder},
|
|
10
11
|
keywords = {Materials, Project, Design, Thermodynamics, High-throughput},
|
|
11
12
|
}
|
|
@@ -33,7 +34,8 @@ journal = {Journal of Physics: Condensed Matter},
|
|
|
33
34
|
pages={175--192},
|
|
34
35
|
year={2011},
|
|
35
36
|
publisher={The Geological Society of London London},
|
|
36
|
-
url={http://dx.doi.org/10.1144/SP360.10}
|
|
37
|
+
url={http://dx.doi.org/10.1144/SP360.10},
|
|
38
|
+
doi={10.1144/SP360.10}
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
@book{nye,
|
|
@@ -124,4 +126,4 @@ DOI = {10.5194/se-11-259-2020}
|
|
|
124
126
|
doi = {10.1038/s41586-020-2649-2},
|
|
125
127
|
publisher = {Springer Science and Business Media {LLC}},
|
|
126
128
|
url = {https://doi.org/10.1038/s41586-020-2649-2}
|
|
127
|
-
}
|
|
129
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: elasticipy
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: A Python library for elasticity tensor computations
|
|
5
5
|
Author-email: Dorian Depriester <dorian.dep@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -36,6 +36,7 @@ Requires-Dist: mp_api; extra == "dev"
|
|
|
36
36
|
[](https://doi.org/10.5281/zenodo.14501849)
|
|
37
37
|
[](https://codecov.io/gh/DorianDepriester/Elasticipy)
|
|
38
38
|

|
|
39
|
+
[](https://joss.theoj.org/papers/8cce91b782f17f52e9ee30916cd86ad5)
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
[](https://doi.org/10.5281/zenodo.14501849)
|
|
7
7
|
[](https://codecov.io/gh/DorianDepriester/Elasticipy)
|
|
8
8
|

|
|
9
|
+
[](https://joss.theoj.org/papers/8cce91b782f17f52e9ee30916cd86ad5)
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
@@ -63,17 +63,17 @@ So now, the plastic strain can be computed using an iterative approach:
|
|
|
63
63
|
|
|
64
64
|
>>> plastic_strain = StrainTensor.zeros(n_step)
|
|
65
65
|
>>> for i in range(1, n_step):
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
... strain_increment = JC.compute_strain_increment(stress[i])
|
|
67
|
+
... plastic_strain[i] = plastic_strain[i-1] + strain_increment
|
|
68
68
|
|
|
69
69
|
That's all. Finally, let us plot the applied stress as a function of the overall elongation:
|
|
70
70
|
|
|
71
71
|
>>> from matplotlib import pyplot as plt
|
|
72
72
|
>>> elong = elastic_strain.C[0,0]+plastic_strain.C[0,0]
|
|
73
73
|
>>> fig, ax = plt.subplots()
|
|
74
|
-
>>> ax.plot(elong, stress_mag, label='Stress-controlled')
|
|
75
|
-
>>> ax.set_xlabel(r'$\varepsilon_{xx}$')
|
|
76
|
-
>>> ax.set_ylabel('Tensile stress (MPa)')
|
|
74
|
+
>>> ax.plot(elong, stress_mag, label='Stress-controlled') # doctest: +SKIP
|
|
75
|
+
>>> ax.set_xlabel(r'$\varepsilon_{xx}$') # doctest: +SKIP
|
|
76
|
+
>>> ax.set_ylabel('Tensile stress (MPa)') # doctest: +SKIP
|
|
77
77
|
|
|
78
78
|
.. image:: images/Stress-controlled.png
|
|
79
79
|
|
|
@@ -90,22 +90,22 @@ to add a subroutine (optimization loop) to find the tensile stress so that the a
|
|
|
90
90
|
>>> plastic_strain = StrainTensor.zeros(n_step)
|
|
91
91
|
>>> JC.reset_strain()
|
|
92
92
|
>>> for i in range(1, n_step):
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
... def fun(tensile_stress):
|
|
94
|
+
... trial_stress = StressTensor.tensile([1,0,0], tensile_stress)
|
|
95
|
+
... trial_elastic_strain = C.inv() * trial_stress
|
|
96
|
+
... trial_strain_increment = JC.compute_strain_increment(trial_stress, apply_strain=False)
|
|
97
|
+
... trial_plastic_strain = plastic_strain[i - 1] + trial_strain_increment
|
|
98
|
+
... trial_elongation = trial_plastic_strain.C[0,0] + trial_elastic_strain.C[0,0]
|
|
99
|
+
... return (trial_elongation - elong[i])**2
|
|
100
|
+
... s = minimize_scalar(fun)
|
|
101
|
+
... stress.C[0,0][i] = s.x
|
|
102
|
+
... strain_increment = JC.compute_strain_increment(stress[i])
|
|
103
|
+
... plastic_strain[i] = plastic_strain[i-1] + strain_increment
|
|
104
104
|
|
|
105
105
|
Finally, let's plot the corresponding tensile curve ontop of that of the stress-controlled tensile test:
|
|
106
106
|
|
|
107
|
-
>>> ax.plot(elong, stress.C[0,0], label='Strain-controlled', linestyle='dotted')
|
|
108
|
-
>>> ax.legend()
|
|
107
|
+
>>> ax.plot(elong, stress.C[0,0], label='Strain-controlled', linestyle='dotted') # doctest: +SKIP
|
|
108
|
+
>>> ax.legend() # doctest: +SKIP
|
|
109
109
|
|
|
110
110
|
.. image:: images/StressStrain-controlled.png
|
|
111
111
|
|
|
@@ -115,10 +115,10 @@ Incremental loading
|
|
|
115
115
|
Here, we have only considered monotonic loading, but we can also consider different loading path, such as incremental:
|
|
116
116
|
|
|
117
117
|
>>> load_path = [np.linspace(0,0.1),
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
... np.linspace(0.1,0.099),
|
|
119
|
+
... np.linspace(0.099,0.2),
|
|
120
|
+
... np.linspace(0.2,0.199),
|
|
121
|
+
... np.linspace(0.199,0.3)]
|
|
122
122
|
>>> elong = np.concatenate(load_path)
|
|
123
123
|
>>> n_step = len(elong)
|
|
124
124
|
|
|
@@ -128,9 +128,9 @@ or cyclic:
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
>>> load_path = [np.linspace(0,0.1),
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
... np.linspace(0.1,-0.2),
|
|
132
|
+
... np.linspace(-0.2,0.3),
|
|
133
|
+
... np.linspace(0.3,-0.4)]
|
|
134
134
|
>>> elong = np.concatenate(load_path)
|
|
135
135
|
>>> n_step = len(elong)
|
|
136
136
|
|
|
@@ -166,15 +166,15 @@ For instance, one can highlight the difference between the J2 and Tresca plastic
|
|
|
166
166
|
>>> elastic_strain = C.inv() * stress
|
|
167
167
|
>>> fig, ax = plt.subplots()
|
|
168
168
|
>>> for j, model in enumerate(models):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
>>> ax.set_xlabel(r'$\varepsilon_{xy}$')
|
|
176
|
-
>>> ax.set_ylabel('Shear stress (MPa)')
|
|
177
|
-
>>> ax.legend()
|
|
169
|
+
... plastic_strain = StrainTensor.zeros(n_step)
|
|
170
|
+
... for i in range(1, n_step):
|
|
171
|
+
... strain_increment = model.compute_strain_increment(stress[i])
|
|
172
|
+
... plastic_strain[i] = plastic_strain[i-1] + strain_increment
|
|
173
|
+
... eps_xy = elastic_strain.C[0,1]+plastic_strain.C[0,1]
|
|
174
|
+
... ax.plot(eps_xy, stress_mag, label=labels[j])
|
|
175
|
+
>>> ax.set_xlabel(r'$\varepsilon_{xy}$') # doctest: +SKIP
|
|
176
|
+
>>> ax.set_ylabel('Shear stress (MPa)') # doctest: +SKIP
|
|
177
|
+
>>> ax.legend() # doctest: +SKIP
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
.. image:: images/Shear.png
|
|
@@ -55,7 +55,7 @@ deviation of the Young modulus:
|
|
|
55
55
|
Another way to evidence anisotropy is to use the universal anisotropy factor [1]_:
|
|
56
56
|
|
|
57
57
|
>>> C.universal_anisotropy
|
|
58
|
-
5.
|
|
58
|
+
5.1410095516414085
|
|
59
59
|
|
|
60
60
|
Shear moduli and Poisson ratios
|
|
61
61
|
-------------------------------
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Stress and strain tensors
|
|
2
|
+
=========================
|
|
3
|
+
|
|
4
|
+
This tutorial illustrates how we work on strain and stress tensors, and how Elasticipy handles arrays of tensors.
|
|
5
|
+
|
|
6
|
+
Single tensors
|
|
7
|
+
--------------
|
|
8
|
+
Let's start with basic operations with the stress tensor. For instance, we can compute the von Mises and Tresca
|
|
9
|
+
equivalent stresses:
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
.. doctest::
|
|
13
|
+
|
|
14
|
+
>>> from Elasticipy.StressStrainTensors import StressTensor, StrainTensor
|
|
15
|
+
>>> stress = StressTensor.shear([1, 0, 0], [0, 1, 0], 1.0) # Unit XY shear stress
|
|
16
|
+
>>> print(stress.vonMises(), stress.Tresca())
|
|
17
|
+
1.7320508075688772 2.0
|
|
18
|
+
|
|
19
|
+
So now, let's have a look on the strain tensor, and compute the principal strains and the volumetric change:
|
|
20
|
+
|
|
21
|
+
>>> strain = StrainTensor.shear([1,0,0], [0,1,0], 1e-3) # XY Shear strain with 1e-3 mag.
|
|
22
|
+
>>> print(strain.principal_strains())
|
|
23
|
+
[ 0.001 0. -0.001]
|
|
24
|
+
>>> print(strain.volumetric_strain())
|
|
25
|
+
0.0
|
|
26
|
+
>>> stress = StressTensor.shear([1, 0, 0], [0, 1, 0], 1.0) # Unit XY shear stress
|
|
27
|
+
>>> print(stress.vonMises(), stress.Tresca())
|
|
28
|
+
1.7320508075688772 2.0
|
|
29
|
+
|
|
30
|
+
Linear elasticity
|
|
31
|
+
--------------------------------
|
|
32
|
+
This section is dedicated to linear elasticity, hence introducing the fourth-order stiffness tensor.
|
|
33
|
+
As an example, create a stiffness tensor corresponding to steel:
|
|
34
|
+
|
|
35
|
+
>>> from Elasticipy.FourthOrderTensor import StiffnessTensor
|
|
36
|
+
>>> C = StiffnessTensor.isotropic(E=210e3, nu=0.28)
|
|
37
|
+
>>> print(C)
|
|
38
|
+
Stiffness tensor (in Voigt notation):
|
|
39
|
+
[[268465.90909091 104403.40909091 104403.40909091 0.
|
|
40
|
+
0. 0. ]
|
|
41
|
+
[104403.40909091 268465.90909091 104403.40909091 0.
|
|
42
|
+
0. 0. ]
|
|
43
|
+
[104403.40909091 104403.40909091 268465.90909091 0.
|
|
44
|
+
0. 0. ]
|
|
45
|
+
[ 0. 0. 0. 82031.25
|
|
46
|
+
0. 0. ]
|
|
47
|
+
[ 0. 0. 0. 0.
|
|
48
|
+
82031.25 0. ]
|
|
49
|
+
[ 0. 0. 0. 0.
|
|
50
|
+
0. 82031.25 ]]
|
|
51
|
+
Symmetry: isotropic
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Considering the previous strain, evaluate the corresponding stress:
|
|
55
|
+
|
|
56
|
+
>>> sigma = C * strain
|
|
57
|
+
>>> print(sigma)
|
|
58
|
+
Stress tensor
|
|
59
|
+
[[ 0. 164.0625 0. ]
|
|
60
|
+
[164.0625 0. 0. ]
|
|
61
|
+
[ 0. 0. 0. ]]
|
|
62
|
+
|
|
63
|
+
Conversely, one can compute the compliance tensor:
|
|
64
|
+
|
|
65
|
+
>>> S = C.inv()
|
|
66
|
+
>>> print(S)
|
|
67
|
+
Compliance tensor (in Voigt notation):
|
|
68
|
+
[[ 4.76190476e-06 -1.33333333e-06 -1.33333333e-06 0.00000000e+00
|
|
69
|
+
0.00000000e+00 0.00000000e+00]
|
|
70
|
+
[-1.33333333e-06 4.76190476e-06 -1.33333333e-06 0.00000000e+00
|
|
71
|
+
0.00000000e+00 0.00000000e+00]
|
|
72
|
+
[-1.33333333e-06 -1.33333333e-06 4.76190476e-06 0.00000000e+00
|
|
73
|
+
0.00000000e+00 0.00000000e+00]
|
|
74
|
+
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.21904762e-05
|
|
75
|
+
0.00000000e+00 0.00000000e+00]
|
|
76
|
+
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
|
|
77
|
+
1.21904762e-05 0.00000000e+00]
|
|
78
|
+
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
|
|
79
|
+
0.00000000e+00 1.21904762e-05]]
|
|
80
|
+
Symmetry: isotropic
|
|
81
|
+
|
|
82
|
+
and check that we retrieve the correct (initial) strain:
|
|
83
|
+
|
|
84
|
+
>>> print(S * sigma)
|
|
85
|
+
Strain tensor
|
|
86
|
+
[[0. 0.001 0. ]
|
|
87
|
+
[0.001 0. 0. ]
|
|
88
|
+
[0. 0. 0. ]]
|
|
89
|
+
|
|
90
|
+
.. _multidimensional-arrays:
|
|
91
|
+
|
|
92
|
+
Multidimensional tensor arrays
|
|
93
|
+
------------------------------
|
|
94
|
+
Elasticipy allows to process thousands of tensors at one, with the aid of tensor arrays.
|
|
95
|
+
As an illustration, we consider the anisotropic behaviour of ferrite:
|
|
96
|
+
|
|
97
|
+
>>> C = StiffnessTensor.fromCrystalSymmetry(symmetry='cubic', phase_name='ferrite',
|
|
98
|
+
... C11=274, C12=175, C44=89)
|
|
99
|
+
>>> print(C)
|
|
100
|
+
Stiffness tensor (in Voigt notation) for ferrite:
|
|
101
|
+
[[274. 175. 175. 0. 0. 0.]
|
|
102
|
+
[175. 274. 175. 0. 0. 0.]
|
|
103
|
+
[175. 175. 274. 0. 0. 0.]
|
|
104
|
+
[ 0. 0. 0. 89. 0. 0.]
|
|
105
|
+
[ 0. 0. 0. 0. 89. 0.]
|
|
106
|
+
[ 0. 0. 0. 0. 0. 89.]]
|
|
107
|
+
Symmetry: cubic
|
|
108
|
+
|
|
109
|
+
Let's start by creating an array of 10 stresses:
|
|
110
|
+
|
|
111
|
+
>>> import numpy as np
|
|
112
|
+
>>> n_array = 10
|
|
113
|
+
>>> shear_stress = np.linspace(0, 100, n_array)
|
|
114
|
+
>>> sigma = StressTensor.shear([1,0,0],[0,1,0], shear_stress) # Array of stresses corresponding to X-Y shear
|
|
115
|
+
>>> print(sigma[0]) # Check the initial value of the stress...
|
|
116
|
+
Stress tensor
|
|
117
|
+
[[0. 0. 0.]
|
|
118
|
+
[0. 0. 0.]
|
|
119
|
+
[0. 0. 0.]]
|
|
120
|
+
>>> print(sigma[-1]) # ...and the final value.
|
|
121
|
+
Stress tensor
|
|
122
|
+
[[ 0. 100. 0.]
|
|
123
|
+
[100. 0. 0.]
|
|
124
|
+
[ 0. 0. 0.]]
|
|
125
|
+
|
|
126
|
+
The corresponding strain array is evaluated with the same syntax as before:
|
|
127
|
+
|
|
128
|
+
>>> eps = C.inv() * sigma
|
|
129
|
+
>>> print(eps[0]) # Now check the initial value of strain...
|
|
130
|
+
Strain tensor
|
|
131
|
+
[[0. 0. 0.]
|
|
132
|
+
[0. 0. 0.]
|
|
133
|
+
[0. 0. 0.]]
|
|
134
|
+
>>> print(eps[-1]) # ...and the final value.
|
|
135
|
+
Strain tensor
|
|
136
|
+
[[0. 0.56179775 0. ]
|
|
137
|
+
[0.56179775 0. 0. ]
|
|
138
|
+
[0. 0. 0. ]]
|
|
139
|
+
|
|
140
|
+
We can for instance compute the corresponding elastic energies:
|
|
141
|
+
|
|
142
|
+
>>> print(eps.elastic_energy(sigma))
|
|
143
|
+
[ 0. 0.69357747 2.77430989 6.24219725 11.09723956 17.33943682
|
|
144
|
+
24.96878901 33.98529616 44.38895825 56.17977528]
|
|
145
|
+
|
|
146
|
+
Another application of working with an array of stress tensors is to check whether a tensor field complies with the
|
|
147
|
+
balance of linear momentum (see `here <https://en.wikiversity.org/wiki/Continuum_mechanics/Balance_of_linear_momentum>`_
|
|
148
|
+
for details) or not. For instance, if we want to compute the divergence of ``sigma``:
|
|
149
|
+
|
|
150
|
+
>>> sigma.div()
|
|
151
|
+
array([[ 0. , 11.11111111, 0. ],
|
|
152
|
+
[ 0. , 11.11111111, 0. ],
|
|
153
|
+
[ 0. , 11.11111111, 0. ],
|
|
154
|
+
[ 0. , 11.11111111, 0. ],
|
|
155
|
+
[ 0. , 11.11111111, 0. ],
|
|
156
|
+
[ 0. , 11.11111111, 0. ],
|
|
157
|
+
[ 0. , 11.11111111, 0. ],
|
|
158
|
+
[ 0. , 11.11111111, 0. ],
|
|
159
|
+
[ 0. , 11.11111111, 0. ],
|
|
160
|
+
[ 0. , 11.11111111, 0. ]])
|
|
161
|
+
|
|
162
|
+
Here, the *i*-th row provides the divergence vector for the *i*-th stress tensor.
|
|
163
|
+
See `the full documentation <../Elasticipy.SecondOrderTensor.html#Elasticipy.SecondOrderTensor.SecondOrderTensor.div>`_ for
|
|
164
|
+
details about this function.
|
|
165
|
+
|
|
166
|
+
.. _strain_rotations:
|
|
167
|
+
|
|
168
|
+
Apply rotations
|
|
169
|
+
---------------
|
|
170
|
+
Rotations can be applied on the tensors. If multiple rotations are applied at once, this results in tensor arrays.
|
|
171
|
+
Rotations are defined by ``scipy.transform.Rotation``
|
|
172
|
+
(see `here <https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html>`__ for details).
|
|
173
|
+
|
|
174
|
+
>>> from scipy.spatial.transform import Rotation
|
|
175
|
+
|
|
176
|
+
For example, let's consider a random set of 1000 rotations:
|
|
177
|
+
|
|
178
|
+
>>> n_ori = 1000
|
|
179
|
+
>>> random_state = 1234 # This is just to ensure reproducibility
|
|
180
|
+
>>> rotations = Rotation.random(n_ori, random_state=random_state)
|
|
181
|
+
|
|
182
|
+
These rotations can be applied on the strain tensor
|
|
183
|
+
|
|
184
|
+
>>> eps_rotated = eps.rotate(rotations, mode='cross')
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
Option ``mode='cross'`` allows to compute all combinations of strains and rotation, resulting in a kind of 2D matrix of
|
|
188
|
+
strain tensors:
|
|
189
|
+
|
|
190
|
+
>>> print(eps_rotated.shape)
|
|
191
|
+
(10, 1000)
|
|
192
|
+
|
|
193
|
+
Therefore, we can compute the corresponding rotated stress array:
|
|
194
|
+
|
|
195
|
+
>>> sigma_rotated = C * eps_rotated
|
|
196
|
+
>>> print(sigma_rotated.shape) # Check out the shape of the stresses
|
|
197
|
+
(10, 1000)
|
|
198
|
+
|
|
199
|
+
And get the stress back to the initial coordinate system:
|
|
200
|
+
|
|
201
|
+
>>> sigma = sigma_rotated * rotations.inv() # Go back to initial frame
|
|
202
|
+
|
|
203
|
+
As opposed to the ``rotate(..., mode='cross')`` (see above), we use ``*`` here to keep the same
|
|
204
|
+
dimensionality (perform element-wise multiplication). It is equivalent to:
|
|
205
|
+
|
|
206
|
+
>>> sigma = sigma_rotated.rotate(rotations.inv())
|
|
207
|
+
|
|
208
|
+
Finally, we can estimate the mean stresses among all the orientations:
|
|
209
|
+
|
|
210
|
+
>>> sigma_mean = sigma.mean(axis=1) # Compute the mean over all orientations
|
|
211
|
+
>>> print(sigma_mean[-1]) # random
|
|
212
|
+
Stress tensor
|
|
213
|
+
[[ 5.35134832e-01 8.22419895e+01 2.02619662e-01]
|
|
214
|
+
[ 8.22419895e+01 -4.88440590e-01 -1.52733598e-01]
|
|
215
|
+
[ 2.02619662e-01 -1.52733598e-01 -4.66942413e-02]]
|
|
216
|
+
|
|
217
|
+
Actually, a more straightforward method is to define a set of rotated stiffness tensors, and compute their Reuss average:
|
|
218
|
+
|
|
219
|
+
>>> C_rotated = C * rotations
|
|
220
|
+
>>> C_Voigt = C_rotated.Voigt_average()
|
|
221
|
+
|
|
222
|
+
Which yields the same results in terms of stress:
|
|
223
|
+
|
|
224
|
+
>>> sigma_Voigt = C_Voigt * eps
|
|
225
|
+
>>> print(sigma_Voigt[-1])
|
|
226
|
+
Stress tensor
|
|
227
|
+
[[ 5.35134832e-01 8.22419895e+01 2.02619662e-01]
|
|
228
|
+
[ 8.22419895e+01 -4.88440590e-01 -1.52733598e-01]
|
|
229
|
+
[ 2.02619662e-01 -1.52733598e-01 -4.66942413e-02]]
|
|
230
|
+
|
|
231
|
+
See :ref:`here<Averaging methods>` for further details about the averaging methods.
|
|
@@ -77,20 +77,24 @@ If we want to consider multiple orientations at once, we can create an array of
|
|
|
77
77
|
Shape=(10000,)
|
|
78
78
|
|
|
79
79
|
If we want to compute the strain for each combination of orientations and temperatures in ``[0,1,2]`` (as done above),
|
|
80
|
-
we can use the ``
|
|
80
|
+
we can use the ``apply_temperature()`` operator with ``mode='cross'``:
|
|
81
81
|
|
|
82
|
-
>>> eps = alpha_rotated.
|
|
82
|
+
>>> eps = alpha_rotated.apply_temperature([0,1,2], mode='cross')
|
|
83
83
|
>>> print(eps)
|
|
84
84
|
Strain tensor
|
|
85
85
|
Shape=(10000, 3)
|
|
86
86
|
|
|
87
|
+
.. note::
|
|
88
|
+
|
|
89
|
+
Above, we have used ``*``, which is just a shortcut for ``apply_temperature(...,mode='pair')``.
|
|
90
|
+
|
|
87
91
|
For instance we can check out the maximum value for initial (0°) and final (2°) temperatures:
|
|
88
92
|
|
|
89
93
|
>>> eps[:,0].max() # 0 because it corresponds to 0°
|
|
90
94
|
Strain tensor
|
|
91
|
-
[[
|
|
92
|
-
[
|
|
93
|
-
[
|
|
95
|
+
[[0. 0. 0.]
|
|
96
|
+
[0. 0. 0.]
|
|
97
|
+
[0. 0. 0.]]
|
|
94
98
|
>>> eps[:,-1].max()
|
|
95
99
|
Strain tensor
|
|
96
100
|
[[1.12000000e-05 5.99947076e-06 5.99905095e-06]
|
|
@@ -32,6 +32,10 @@ Welcome to Elasticipy's Documentation!
|
|
|
32
32
|
.. image:: https://img.shields.io/pypi/pyversions/Elasticipy
|
|
33
33
|
:alt: PyPI - Python Version
|
|
34
34
|
|
|
35
|
+
.. image:: https://joss.theoj.org/papers/8cce91b782f17f52e9ee30916cd86ad5/status.svg
|
|
36
|
+
:alt: JOSS status
|
|
37
|
+
:target: https://joss.theoj.org/papers/8cce91b782f17f52e9ee30916cd86ad5
|
|
38
|
+
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
Purpose of this package
|