elasticipy 4.1.1__py3-none-any.whl → 5.0.0__py3-none-any.whl
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/gui.py +101 -2
- Elasticipy/interfaces/FEPX.py +3 -3
- Elasticipy/plasticity.py +179 -34
- Elasticipy/spherical_function.py +43 -4
- Elasticipy/tensors/elasticity.py +1032 -203
- Elasticipy/tensors/fourth_order.py +895 -172
- Elasticipy/tensors/mapping.py +48 -0
- Elasticipy/tensors/second_order.py +49 -7
- Elasticipy/tensors/stress_strain.py +209 -3
- Elasticipy/tensors/thermal_expansion.py +6 -1
- {elasticipy-4.1.1.dist-info → elasticipy-5.0.0.dist-info}/METADATA +40 -21
- elasticipy-5.0.0.dist-info/RECORD +24 -0
- elasticipy-5.0.0.dist-info/entry_points.txt +2 -0
- elasticipy-4.1.1.dist-info/RECORD +0 -23
- {elasticipy-4.1.1.dist-info → elasticipy-5.0.0.dist-info}/WHEEL +0 -0
- {elasticipy-4.1.1.dist-info → elasticipy-5.0.0.dist-info}/licenses/LICENSE +0 -0
- {elasticipy-4.1.1.dist-info → elasticipy-5.0.0.dist-info}/top_level.txt +0 -0
Elasticipy/tensors/mapping.py
CHANGED
|
@@ -16,6 +16,17 @@ VOIGT_MAPPING_MATRIX_COMPLIANCE = [[1, 1, 1, 2, 2, 2],
|
|
|
16
16
|
[2, 2, 2, 4, 4, 4]]
|
|
17
17
|
|
|
18
18
|
class MappingConvention:
|
|
19
|
+
"""
|
|
20
|
+
Generic class for defining the mapping convention to build a 4th-order tensor from a (6,6) matrix, and the mapping
|
|
21
|
+
convention to use for reciprocal tensor.
|
|
22
|
+
|
|
23
|
+
Attributes
|
|
24
|
+
----------
|
|
25
|
+
matrix : numpy.ndarray
|
|
26
|
+
(6,6) matrix evidencing the coefficient between the 4-index and the 2-index notations
|
|
27
|
+
mapping_inverse : MappingConvention
|
|
28
|
+
Mapping convention to use for the reciprocal tensor
|
|
29
|
+
"""
|
|
19
30
|
matrix = np.array(KELVIN_MAPPING_MATRIX)
|
|
20
31
|
|
|
21
32
|
@property
|
|
@@ -29,6 +40,43 @@ class VoigtMapping(MappingConvention):
|
|
|
29
40
|
name = 'Voigt'
|
|
30
41
|
|
|
31
42
|
def __init__(self, tensor='Stiffness'):
|
|
43
|
+
"""
|
|
44
|
+
Create a Voigt mapping convention.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
tensor : str
|
|
49
|
+
It can be 'stiffness' or 'compliance'
|
|
50
|
+
Type of tensor we define. Depending on this, the mapping convention will change (see notes).
|
|
51
|
+
|
|
52
|
+
Notes
|
|
53
|
+
-----
|
|
54
|
+
For stiffness-like tensors (if ``tensor=stiffness``), the mapping matrix will be:
|
|
55
|
+
|
|
56
|
+
.. math::
|
|
57
|
+
|
|
58
|
+
\\begin{bmatrix}
|
|
59
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
60
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
61
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
62
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
63
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
64
|
+
1 & 1 & 1 & 1 & 1 & 1\\\\
|
|
65
|
+
\end{bmatrix}
|
|
66
|
+
|
|
67
|
+
Conversely, for compliance-like tensors (if ``tensor=compliance``), the mapping matrix will be:
|
|
68
|
+
|
|
69
|
+
.. math::
|
|
70
|
+
|
|
71
|
+
\\begin{bmatrix}
|
|
72
|
+
1 & 1 & 1 & \\sqrt{2} & \\sqrt{2} & \\sqrt{2}\\\\
|
|
73
|
+
1 & 1 & 1 & \\sqrt{2} & \\sqrt{2} & \\sqrt{2}\\\\
|
|
74
|
+
1 & 1 & 1 & \\sqrt{2} & \\sqrt{2} & \\sqrt{2}\\\\
|
|
75
|
+
\\sqrt{2} & \\sqrt{2} & \\sqrt{2} & 2 & 2 & 2\\\\
|
|
76
|
+
\\sqrt{2} & \\sqrt{2} & \\sqrt{2} & 2 & 2 & 2\\\\
|
|
77
|
+
\\sqrt{2} & \\sqrt{2} & \\sqrt{2} & 2 & 2 & 2\\\\
|
|
78
|
+
\end{bmatrix}
|
|
79
|
+
"""
|
|
32
80
|
if tensor == 'Stiffness':
|
|
33
81
|
self.matrix = np.ones((6,6))
|
|
34
82
|
self.tensor_type = 'Stiffness'
|
|
@@ -550,10 +550,8 @@ class SecondOrderTensor:
|
|
|
550
550
|
tensor or tensor array to compute the product from
|
|
551
551
|
mode : str, optional
|
|
552
552
|
If 'pair' (default), the contraction products of tensor arrays are applied element-wise. Broadcasting rule
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
If 'cross', all combinations of contraction product are considered. If ``C=A.dot(B,mode='cross')``, then
|
|
556
|
-
``C.shape==A.shape + B.shape``
|
|
553
|
+
applies. If 'cross', all combinations of contraction product are considered. If ``C=A.dot(B,mode='cross')``,
|
|
554
|
+
then ``C.shape==A.shape + B.shape``.
|
|
557
555
|
|
|
558
556
|
Returns
|
|
559
557
|
-------
|
|
@@ -1216,6 +1214,50 @@ class SecondOrderTensor:
|
|
|
1216
1214
|
:math:`\\mathbf{b}` is the body force density and :math:`\\rho` is the mass density.
|
|
1217
1215
|
|
|
1218
1216
|
In this function, the derivatives are computed with ``numpy.grad`` function.
|
|
1217
|
+
|
|
1218
|
+
Examples
|
|
1219
|
+
--------
|
|
1220
|
+
First, we build an array of tensile stress with evenly spaced magnitude:
|
|
1221
|
+
|
|
1222
|
+
>>> from Elasticipy.tensors.stress_strain import StressTensor
|
|
1223
|
+
>>> magnitude = [0,1,2,3,4]
|
|
1224
|
+
>>> s = StressTensor.tensile([1,0,0],magnitude)
|
|
1225
|
+
>>> s.div()
|
|
1226
|
+
array([[1., 0., 0.],
|
|
1227
|
+
[1., 0., 0.],
|
|
1228
|
+
[1., 0., 0.],
|
|
1229
|
+
[1., 0., 0.],
|
|
1230
|
+
[1., 0., 0.]])
|
|
1231
|
+
|
|
1232
|
+
We now create a stress tensor whose components follows this:
|
|
1233
|
+
|
|
1234
|
+
.. math::
|
|
1235
|
+
|
|
1236
|
+
\\sigma_{xx} = 2x+3y^2
|
|
1237
|
+
\\sigma_{yy} = y^2+z
|
|
1238
|
+
\\sigma_{xy} = xy
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
To do this, we consider a regular grid of 0.1 in a unit cube:
|
|
1242
|
+
|
|
1243
|
+
>>> import numpy as np
|
|
1244
|
+
>>> spacing = 0.1
|
|
1245
|
+
>>> x,y,z=np.meshgrid(np.arange(0,1,spacing),np.arange(0,1,spacing),np.arange(0,1,spacing), indexing='ij')
|
|
1246
|
+
>>> s_xx = 2*x + 3*y**2
|
|
1247
|
+
>>> s_yy = y**2+z
|
|
1248
|
+
>>> s_xy = x*y
|
|
1249
|
+
>>> s = StressTensor.tensile([1,0,0],s_xx) + StressTensor.tensile([0,1,0],s_yy) + StressTensor.shear([1,0,0],[0,1,0],s_xy)
|
|
1250
|
+
>>> div = s.div(spacing = 0.1)
|
|
1251
|
+
|
|
1252
|
+
As we work here in 3D, the result is of shape (10,10,10,3):
|
|
1253
|
+
|
|
1254
|
+
>>> div.shape
|
|
1255
|
+
(10, 10, 10, 3)
|
|
1256
|
+
|
|
1257
|
+
For instance, the divergence at x=y=z=0 is:
|
|
1258
|
+
|
|
1259
|
+
>>> div[0,0,0,:]
|
|
1260
|
+
array([2. , 0.1, 0. ])
|
|
1219
1261
|
"""
|
|
1220
1262
|
ndim = min(self.ndim, 3) # Even if the array has more than 3Ds, we restrict to 3D
|
|
1221
1263
|
if isinstance(spacing, (float, int)):
|
|
@@ -1438,7 +1480,7 @@ class SecondOrderTensor:
|
|
|
1438
1480
|
|
|
1439
1481
|
|
|
1440
1482
|
class SymmetricSecondOrderTensor(SecondOrderTensor):
|
|
1441
|
-
|
|
1483
|
+
_voigt_map = [1, 1, 1, 1, 1, 1]
|
|
1442
1484
|
"List of factors to use for building a tensor from Voigt vector(s)"
|
|
1443
1485
|
|
|
1444
1486
|
name = 'Symmetric second-order tensor'
|
|
@@ -1530,7 +1572,7 @@ class SymmetricSecondOrderTensor(SecondOrderTensor):
|
|
|
1530
1572
|
[13. 23. 33.]]
|
|
1531
1573
|
"""
|
|
1532
1574
|
if voigt_map is None:
|
|
1533
|
-
voigt_map = cls.
|
|
1575
|
+
voigt_map = cls._voigt_map
|
|
1534
1576
|
matrix = _unmap(array, voigt_map)
|
|
1535
1577
|
return cls(matrix)
|
|
1536
1578
|
|
|
@@ -1545,7 +1587,7 @@ class SymmetricSecondOrderTensor(SecondOrderTensor):
|
|
|
1545
1587
|
numpy.ndarray
|
|
1546
1588
|
Voigt vector summarizing the components
|
|
1547
1589
|
"""
|
|
1548
|
-
return _map(self.matrix, self.
|
|
1590
|
+
return _map(self.matrix, self._voigt_map)
|
|
1549
1591
|
|
|
1550
1592
|
@classmethod
|
|
1551
1593
|
def from_Kelvin(cls, array):
|
|
@@ -8,7 +8,7 @@ class StrainTensor(SymmetricSecondOrderTensor):
|
|
|
8
8
|
|
|
9
9
|
"""
|
|
10
10
|
name = 'Strain tensor'
|
|
11
|
-
|
|
11
|
+
_voigt_map = [1, 1, 1, 2, 2, 2]
|
|
12
12
|
|
|
13
13
|
def principal_strains(self):
|
|
14
14
|
"""
|
|
@@ -20,6 +20,25 @@ class StrainTensor(SymmetricSecondOrderTensor):
|
|
|
20
20
|
-------
|
|
21
21
|
np.ndarray
|
|
22
22
|
Principal strain values
|
|
23
|
+
|
|
24
|
+
Examples
|
|
25
|
+
--------
|
|
26
|
+
For a single strain value, the principal strain values are composed of 3 float. E.g.:
|
|
27
|
+
|
|
28
|
+
>>> from Elasticipy.tensors.stress_strain import StrainTensor
|
|
29
|
+
>>> eps = StrainTensor.shear([1,0,0],[0,1,0],1e-3)
|
|
30
|
+
>>> eps.principal_strains()
|
|
31
|
+
array([ 0.001, 0. , -0.001])
|
|
32
|
+
|
|
33
|
+
For strain tensor array, the shape of the returned array will depend on that of the strain array. E.g.:
|
|
34
|
+
|
|
35
|
+
>>> tau = [1,2,3,4] # increasing magnitude
|
|
36
|
+
>>> eps_2d = StrainTensor.shear([1,0,0],[0,1,0],tau)/1000
|
|
37
|
+
>>> eps_2d.principal_strains()
|
|
38
|
+
array([[ 0.001, 0. , -0.001],
|
|
39
|
+
[ 0.002, 0. , -0.002],
|
|
40
|
+
[ 0.003, 0. , -0.003],
|
|
41
|
+
[ 0.004, 0. , -0.004]])
|
|
23
42
|
"""
|
|
24
43
|
return self.eigvals()
|
|
25
44
|
|
|
@@ -31,11 +50,54 @@ class StrainTensor(SymmetricSecondOrderTensor):
|
|
|
31
50
|
-------
|
|
32
51
|
numpy.ndarray or float
|
|
33
52
|
Volumetric change
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
At first, try with pure shear:
|
|
57
|
+
|
|
58
|
+
>>> from Elasticipy.tensors.stress_strain import StrainTensor
|
|
59
|
+
>>> eps = StrainTensor.shear([1,0,0],[0,1,0],1e-3)
|
|
60
|
+
>>> eps.volumetric_strain()
|
|
61
|
+
0.0
|
|
62
|
+
|
|
63
|
+
Now try with hydrastatic straining:
|
|
64
|
+
|
|
65
|
+
>>> import numpy as np
|
|
66
|
+
>>> eps_hydro = StrainTensor(-np.eye(3)) / 1000
|
|
67
|
+
>>> eps_hydro
|
|
68
|
+
Strain tensor
|
|
69
|
+
[[-0.001 -0. -0. ]
|
|
70
|
+
[-0. -0.001 -0. ]
|
|
71
|
+
[-0. -0. -0.001]]
|
|
72
|
+
>>> eps_hydro.volumetric_strain()
|
|
73
|
+
-0.003
|
|
34
74
|
"""
|
|
35
75
|
return self.I1
|
|
36
76
|
|
|
37
77
|
def eq_strain(self):
|
|
38
|
-
"""von Mises equivalent strain
|
|
78
|
+
"""von Mises equivalent strain
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
numpy.ndarray or float
|
|
83
|
+
If the input tensor is single, the result will be float. Instead, an Numpy array will be returned.
|
|
84
|
+
|
|
85
|
+
Notes
|
|
86
|
+
-----
|
|
87
|
+
The von Mises equivalent strain is defined as:
|
|
88
|
+
|
|
89
|
+
.. math::
|
|
90
|
+
|
|
91
|
+
\\sqrt{\\frac23 \\varepsilon_{ij}\\varepsilon_{ij}}
|
|
92
|
+
|
|
93
|
+
Examples
|
|
94
|
+
--------
|
|
95
|
+
>>> from Elasticipy.tensors.stress_strain import StrainTensor
|
|
96
|
+
>>> StrainTensor.tensile([1,0,0], 1e-3).eq_strain()
|
|
97
|
+
0.000816496580927726
|
|
98
|
+
>>> StrainTensor.shear([1,0,0],[0,1,0], 1e-3).eq_strain()
|
|
99
|
+
0.0011547005383792514
|
|
100
|
+
"""
|
|
39
101
|
return np.sqrt(2/3 * self.ddot(self))
|
|
40
102
|
|
|
41
103
|
def elastic_energy(self, stress, mode='pair'):
|
|
@@ -54,6 +116,27 @@ class StrainTensor(SymmetricSecondOrderTensor):
|
|
|
54
116
|
-------
|
|
55
117
|
float or numpy.ndarray
|
|
56
118
|
Volumetric elastic energy
|
|
119
|
+
|
|
120
|
+
Examples
|
|
121
|
+
--------
|
|
122
|
+
Let consider an isotropic material (e.g. steel), undergoing tensile strain. In order to compute the volumetric
|
|
123
|
+
elastic energy, one can do the following:
|
|
124
|
+
|
|
125
|
+
>>> from Elasticipy.tensors.stress_strain import StrainTensor
|
|
126
|
+
>>> from Elasticipy.tensors.elasticity import StiffnessTensor
|
|
127
|
+
>>> C = StiffnessTensor.isotropic(E=210e3, nu=0.28)
|
|
128
|
+
>>> eps = StrainTensor.tensile([1,0,0],1e-3) # Define the strain
|
|
129
|
+
>>> sigma = C * eps # Compute the stress
|
|
130
|
+
>>> sigma
|
|
131
|
+
Stress tensor
|
|
132
|
+
[[268.46590909 0. 0. ]
|
|
133
|
+
[ 0. 104.40340909 0. ]
|
|
134
|
+
[ 0. 0. 104.40340909]]
|
|
135
|
+
|
|
136
|
+
Then, the volumetric elastic energy is:
|
|
137
|
+
|
|
138
|
+
>>> eps.elastic_energy(sigma)
|
|
139
|
+
0.13423295454545456
|
|
57
140
|
"""
|
|
58
141
|
return 0.5 * self.ddot(stress, mode=mode)
|
|
59
142
|
|
|
@@ -95,6 +178,30 @@ class StressTensor(SymmetricSecondOrderTensor):
|
|
|
95
178
|
See Also
|
|
96
179
|
--------
|
|
97
180
|
Tresca : Tresca equivalent stress
|
|
181
|
+
|
|
182
|
+
Examples
|
|
183
|
+
--------
|
|
184
|
+
For (single-valued) tensile stress:
|
|
185
|
+
|
|
186
|
+
>>> from Elasticipy.tensors.stress_strain import StressTensor
|
|
187
|
+
>>> sigma = StressTensor.tensile([1,0,0],1)
|
|
188
|
+
>>> sigma.vonMises()
|
|
189
|
+
1.0
|
|
190
|
+
|
|
191
|
+
For (single-valued) shear stress:
|
|
192
|
+
|
|
193
|
+
>>> sigma = StressTensor.shear([1,0,0],[0,1,0],1)
|
|
194
|
+
>>> sigma.vonMises()
|
|
195
|
+
1.7320508075688772
|
|
196
|
+
|
|
197
|
+
For arrays of stresses :
|
|
198
|
+
|
|
199
|
+
>>> import numpy as np
|
|
200
|
+
>>> sigma_xx = np.linspace(0,1,5)
|
|
201
|
+
>>> sigma_xy = np.linspace(0,1,5)
|
|
202
|
+
>>> sigma = StressTensor.tensile([1,0,0],sigma_xx) + StressTensor.shear([1,0,0],[0,1,0],sigma_xy)
|
|
203
|
+
>>> sigma.vonMises()
|
|
204
|
+
array([-0. , 0.5, 1. , 1.5, 2. ])
|
|
98
205
|
"""
|
|
99
206
|
return np.sqrt(3 * self.J2)
|
|
100
207
|
|
|
@@ -110,6 +217,30 @@ class StressTensor(SymmetricSecondOrderTensor):
|
|
|
110
217
|
See Also
|
|
111
218
|
--------
|
|
112
219
|
vonMises : von Mises equivalent stress
|
|
220
|
+
|
|
221
|
+
Examples
|
|
222
|
+
--------
|
|
223
|
+
For (single-valued) tensile stress:
|
|
224
|
+
|
|
225
|
+
>>> from Elasticipy.tensors.stress_strain import StressTensor
|
|
226
|
+
>>> sigma = StressTensor.tensile([1,0,0],1)
|
|
227
|
+
>>> sigma.Tresca()
|
|
228
|
+
1.0
|
|
229
|
+
|
|
230
|
+
For (single-valued) shear stress:
|
|
231
|
+
|
|
232
|
+
>>> sigma = StressTensor.shear([1,0,0],[0,1,0],1)
|
|
233
|
+
>>> sigma.Tresca()
|
|
234
|
+
2.0
|
|
235
|
+
|
|
236
|
+
For arrays of stresses :
|
|
237
|
+
|
|
238
|
+
>>> import numpy as np
|
|
239
|
+
>>> sigma_xx = np.linspace(0,1,5)
|
|
240
|
+
>>> sigma_xy = np.linspace(0,1,5)
|
|
241
|
+
>>> sigma = StressTensor.tensile([1,0,0],sigma_xx) + StressTensor.shear([1,0,0],[0,1,0],sigma_xy)
|
|
242
|
+
>>> sigma.Tresca()
|
|
243
|
+
array([0. , 0.55901699, 1.11803399, 1.67705098, 2.23606798])
|
|
113
244
|
"""
|
|
114
245
|
ps = self.principal_stresses()
|
|
115
246
|
return ps[...,0] - ps[...,-1]
|
|
@@ -148,7 +279,82 @@ class StressTensor(SymmetricSecondOrderTensor):
|
|
|
148
279
|
return 0.5 * self.ddot(strain, mode=mode)
|
|
149
280
|
|
|
150
281
|
def draw_Mohr_circles(self):
|
|
282
|
+
"""
|
|
283
|
+
Draw the Mohr circles of the stress tensor.
|
|
284
|
+
|
|
285
|
+
This function only works for single-valued tensors.
|
|
286
|
+
|
|
287
|
+
Returns
|
|
288
|
+
-------
|
|
289
|
+
fig : matplotlib.figure.Figure
|
|
290
|
+
handle to Matplotlib figure
|
|
291
|
+
ax : matplotlib.axes.Axes
|
|
292
|
+
handle to Matplotlib axes
|
|
293
|
+
|
|
294
|
+
Examples
|
|
295
|
+
--------
|
|
296
|
+
In order to illustrate this function, we consider a triaxial tensile stress:
|
|
297
|
+
|
|
298
|
+
>>> from Elasticipy.tensors.stress_strain import StressTensor
|
|
299
|
+
>>> sigma = StressTensor.tensile([1,0,0],1) + StressTensor.tensile([0,1,0],3)
|
|
300
|
+
|
|
301
|
+
The princiapl stresses are obviously 0, 1 and 2:
|
|
302
|
+
|
|
303
|
+
>>> sigma.principal_stresses()
|
|
304
|
+
array([3., 1., 0.])
|
|
305
|
+
|
|
306
|
+
These principal stresses can be directly plotted with:
|
|
307
|
+
|
|
308
|
+
>>> fig, ax = sigma.draw_Mohr_circles()
|
|
309
|
+
>>> fig.show()
|
|
310
|
+
"""
|
|
151
311
|
fig, ax = super().draw_Mohr_circles()
|
|
152
312
|
ax.set_xlabel(ax.get_xlabel() + ' stress')
|
|
153
313
|
ax.set_ylabel(ax.get_ylabel() + ' stress')
|
|
154
|
-
return fig, ax
|
|
314
|
+
return fig, ax
|
|
315
|
+
|
|
316
|
+
def triaxiality(self):
|
|
317
|
+
"""
|
|
318
|
+
Compute the stress triaxiality.
|
|
319
|
+
|
|
320
|
+
It is defined as the hydrostatic stress to the von Mises equivalent stress ratio (see Notes).
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
float or np.ndarray
|
|
325
|
+
Stress triaxiality. A float is returned if the tensor is single-valued, otherwise, an array of the same
|
|
326
|
+
shape of the tensor is returned.
|
|
327
|
+
|
|
328
|
+
See Also
|
|
329
|
+
--------
|
|
330
|
+
hydrostatic_pressure : compute the hydrostatic pressure
|
|
331
|
+
vonMises : compute the von Mises equivalent stress
|
|
332
|
+
Lode_angle : compute the Lode angle
|
|
333
|
+
|
|
334
|
+
Notes
|
|
335
|
+
-----
|
|
336
|
+
The stress triaxiality is defined as follows:
|
|
337
|
+
|
|
338
|
+
.. math::
|
|
339
|
+
|
|
340
|
+
\\eta = \\frac{-p}{\\sigma_{vM}}
|
|
341
|
+
|
|
342
|
+
where :math:`p` and :math:`\\sigma_{vM}` are the hydrostatic pressure and the von Mises equivalent stress,
|
|
343
|
+
respectively.
|
|
344
|
+
|
|
345
|
+
Examples
|
|
346
|
+
--------
|
|
347
|
+
One can check that the stress triaxiality is for simple tensile is 1/3:
|
|
348
|
+
|
|
349
|
+
>>> from Elasticipy.tensors.stress_strain import StressTensor
|
|
350
|
+
>>> s1 = StressTensor.tensile([1,0,0],1.)
|
|
351
|
+
>>> s1.triaxiality()
|
|
352
|
+
0.3333333333333333
|
|
353
|
+
|
|
354
|
+
For a stress array (e.g. for biaxial tensile stress):
|
|
355
|
+
|
|
356
|
+
>>> s2 = s1 + StressTensor.tensile([0,1,0],[0,0.5,1])
|
|
357
|
+
>>> s2.triaxiality()
|
|
358
|
+
array([0.33333333, 0.57735027, 0.66666667])
|
|
359
|
+
"""
|
|
360
|
+
return self.I1 / self.vonMises() / 3
|
|
@@ -40,14 +40,17 @@ class ThermalExpansionTensor(SymmetricSecondOrderTensor):
|
|
|
40
40
|
Examples
|
|
41
41
|
--------
|
|
42
42
|
Let consider a transverse isotropic case (e.g. carbon fibers):
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
>>> from Elasticipy.tensors.thermal_expansion import ThermalExpansionTensor as ThEx
|
|
44
45
|
>>> alpha = ThEx.transverse_isotropic(alpha_11=5.6e-6, alpha_33=-0.4e-6)
|
|
45
46
|
|
|
46
47
|
Now apply temperature increases:
|
|
48
|
+
|
|
47
49
|
>>> T = [0, 1, 2]
|
|
48
50
|
>>> eps = alpha.apply_temperature(T)
|
|
49
51
|
|
|
50
52
|
We get a strain tensor of the same shape as the applied temperatures:
|
|
53
|
+
|
|
51
54
|
>>> eps
|
|
52
55
|
Strain tensor
|
|
53
56
|
Shape=(3,)
|
|
@@ -58,11 +61,13 @@ class ThermalExpansionTensor(SymmetricSecondOrderTensor):
|
|
|
58
61
|
[ 0.00e+00 0.00e+00 -8.00e-07]]
|
|
59
62
|
|
|
60
63
|
Now let's rotate the thermal expansions:
|
|
64
|
+
|
|
61
65
|
>>> from scipy.spatial.transform import Rotation
|
|
62
66
|
>>> rot = Rotation.random(3) # Set of 3 random 3D rotations
|
|
63
67
|
>>> alpha_rotated = alpha * rot
|
|
64
68
|
|
|
65
69
|
If we want to combine each rotated thermal expansion with the corresponding temperature increase:
|
|
70
|
+
|
|
66
71
|
>>> eps_rotated_pair = alpha_rotated * T # Equivalent to alpha_rotated.apply_temperature(T)
|
|
67
72
|
>>> eps_rotated_pair
|
|
68
73
|
Strain tensor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elasticipy
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.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
|
|
@@ -12,13 +12,14 @@ Classifier: Development Status :: 4 - Beta
|
|
|
12
12
|
Classifier: Intended Audience :: Science/Research
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Requires-Python: >=3.
|
|
19
|
+
Requires-Python: >=3.9
|
|
19
20
|
Description-Content-Type: text/markdown
|
|
20
21
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: numpy>=1.20.0
|
|
22
23
|
Requires-Dist: scipy
|
|
23
24
|
Requires-Dist: matplotlib
|
|
24
25
|
Requires-Dist: qtpy
|
|
@@ -34,19 +35,24 @@ Dynamic: license-file
|
|
|
34
35
|
|
|
35
36
|
[](https://pypi.org/project/elasticipy/)
|
|
36
37
|
[](https://pypistats.org/packages/elasticipy)
|
|
38
|
+
[](https://anaconda.org/channels/conda-forge/packages/elasticipy/overview)
|
|
39
|
+

|
|
40
|
+

|
|
41
|
+

|
|
37
42
|
[](https://github.com/DorianDepriester/Elasticipy/blob/main/LICENSE)
|
|
38
43
|
[](https://elasticipy.readthedocs.io/)
|
|
39
|
-
[](https://doi.org/10.5281/zenodo.14501849)
|
|
40
44
|
[](https://codecov.io/gh/DorianDepriester/Elasticipy)
|
|
41
45
|

|
|
42
|
-
[](https://doi.org/10.21105/joss.07940)
|
|
47
|
+
[](https://mybinder.org/v2/gh/DorianDepriester/Elasticipy/HEAD?urlpath=%2Fdoc%2Ftree%2FElasticipy_for_the_Impatient.ipynb)
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
|
|
50
|
+
# 
|
|
45
51
|
|
|
46
52
|
A python toolkit to manipulate stress and strain tensors, and other linear elasticity-related tensors (e.g. stiffness).
|
|
47
53
|
This package also provides a collection of easy-to-use and very fast tools to work on stress and strain tensors.
|
|
48
54
|
|
|
49
|
-
## Main features
|
|
55
|
+
## :rocket: Main features
|
|
50
56
|
Among other features, this package implements:
|
|
51
57
|
|
|
52
58
|
- Computation of elasticity tensors,
|
|
@@ -60,19 +66,29 @@ Among other features, this package implements:
|
|
|
60
66
|
- Compatibility with the [Materials Project](https://next-gen.materialsproject.org/) API, [pymatgen](https://pymatgen.org/) and
|
|
61
67
|
[orix](https://orix.readthedocs.io/).
|
|
62
68
|
|
|
63
|
-
## Installation
|
|
69
|
+
## :snake: Installation
|
|
64
70
|
Elasticipy can be installed with PIP:
|
|
65
71
|
````
|
|
66
72
|
pip install Elasticipy
|
|
67
73
|
````
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
On anaconda, one can also use:
|
|
76
|
+
````
|
|
77
|
+
conda install conda-forge::elasticipy
|
|
78
|
+
````
|
|
79
|
+
|
|
80
|
+
## :books: Documentation
|
|
70
81
|
Tutorials and full documentation are available on [ReadTheDoc](https://elasticipy.readthedocs.io/).
|
|
71
82
|
|
|
72
|
-
##
|
|
83
|
+
## :hourglass_flowing_sand: Elasticipy in a nutshell
|
|
84
|
+
Take a 5-minute tour through Elasticipy's main features by running the online Jupyter Notebook, hosted on
|
|
85
|
+
[Binder](https://mybinder.org/v2/gh/DorianDepriester/Elasticipy/HEAD?urlpath=%2Fdoc%2Ftree%2FElasticipy_for_the_Impatient.ipynb).
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## :mag: Sources
|
|
73
89
|
The source code is available on [GitHub](https://github.com/DorianDepriester/Elasticipy) under the [MIT licence](https://github.com/DorianDepriester/Elasticipy/blob/c6c3d441a2d290ab8f4939992d5d753a1ad3bdb0/LICENSE).
|
|
74
90
|
|
|
75
|
-
## Tests and Code Coverage
|
|
91
|
+
## :umbrella: Tests and Code Coverage
|
|
76
92
|
|
|
77
93
|
The project uses unit tests with `pytest` and coverage reports generated using `coverage`. These reports are hosted on
|
|
78
94
|
[codecov](https://app.codecov.io/gh/DorianDepriester/Elasticipy).
|
|
@@ -83,18 +99,21 @@ Certain parts of the code, particularly those related to graphical user interfac
|
|
|
83
99
|
|
|
84
100
|
- **`src/Elasticipy/gui.py`**
|
|
85
101
|
|
|
86
|
-
## Cite this package
|
|
87
|
-
If you use Elasticipy, please cite [](https://doi.org/10.21105/joss.07940)
|
|
88
104
|
|
|
89
105
|
You can use the following BibTeX entry:
|
|
90
106
|
````bibtex
|
|
91
|
-
@
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
@article{Elasticipy,
|
|
108
|
+
doi = {10.21105/joss.07940},
|
|
109
|
+
url = {https://doi.org/10.21105/joss.07940},
|
|
110
|
+
year = {2025},
|
|
111
|
+
publisher = {The Open Journal},
|
|
112
|
+
volume = {10},
|
|
113
|
+
number = {115},
|
|
114
|
+
pages = {7940},
|
|
115
|
+
author = {Depriester, Dorian and Kubler, Régis},
|
|
116
|
+
title = {Elasticipy: A Python package for linear elasticity and tensor analysis},
|
|
117
|
+
journal = {Journal of Open Source Software}
|
|
99
118
|
}
|
|
100
119
|
````
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Elasticipy/FourthOrderTensor.py,sha256=jKXGD69Zas5CKQfeSz-AgLfeYX2XN-O6Q6lGtBKuoiU,508
|
|
2
|
+
Elasticipy/StressStrainTensors.py,sha256=xs4wgG1ohx3pT-X5GZUlm511SazHPsD_-okn822NqCA,491
|
|
3
|
+
Elasticipy/ThermalExpansion.py,sha256=O7VlU_8prjUzlVhQ4N-J66Zhs89S7TqllepUOQ-psJM,411
|
|
4
|
+
Elasticipy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
Elasticipy/crystal_symmetries.py,sha256=DAX-XPgYqI2nFvf6anCVvZ5fLM0CNSDJ7r2h15l3Hoc,3958
|
|
6
|
+
Elasticipy/gui.py,sha256=pFFfXT5ntMx4ZbT6vCCK2YMG09hdLcOWghQUpdXVOmQ,15293
|
|
7
|
+
Elasticipy/plasticity.py,sha256=5VrCIqO7Rx5xf-ZTk366af36vvIKpNTxS0EfZRoG8dY,16756
|
|
8
|
+
Elasticipy/polefigure.py,sha256=-Qrf5B4_m8HSlwXfOntie75EUqKnFsl7ZeXx9lNPUsY,4119
|
|
9
|
+
Elasticipy/spherical_function.py,sha256=JqNyRywDI8dte8KKQTVuAY88vvKlyHGpDB2WDKLGzdI,42380
|
|
10
|
+
Elasticipy/interfaces/FEPX.py,sha256=B1e-moj-l9pDPsp0IrXjim72JbtdJASe8gTdWAWxi3o,4233
|
|
11
|
+
Elasticipy/interfaces/PRISMS.py,sha256=jAHFS2ybbAK2ZcqF9AmnlDTR2JZZMwlgy-FhQIINSAI,3835
|
|
12
|
+
Elasticipy/tensors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
Elasticipy/tensors/elasticity.py,sha256=b1ntHudvY23XFyC-mETawtPA6Xz_hwX3h7GDEkv8ojU,98391
|
|
14
|
+
Elasticipy/tensors/fourth_order.py,sha256=GOYKB_fEPDl72j8Hh9L1jUbjfy4vYw81tjcvwbcN7xE,49577
|
|
15
|
+
Elasticipy/tensors/mapping.py,sha256=K9SQDLgg3jW3rpDYzdpwcOJQRf04iSw7xjj8N3fHwT8,3178
|
|
16
|
+
Elasticipy/tensors/second_order.py,sha256=yrTcW2MIGBsSiTWW_P7l3juCAJrh2ka5k9RC5dEKH5E,57073
|
|
17
|
+
Elasticipy/tensors/stress_strain.py,sha256=wvUwIKiM5TlTkvwmu_NAt4rFpNRGuJ3AU9QU-H6zAiI,10566
|
|
18
|
+
Elasticipy/tensors/thermal_expansion.py,sha256=s3YvEOiqZ7qwGGErXswWv0hCFTq5bRR3nbBrpObgam0,8648
|
|
19
|
+
elasticipy-5.0.0.dist-info/licenses/LICENSE,sha256=qNthTMSjVkIDM1_BREgVFQHdn1wVNQi9pwWVfTIazMA,1074
|
|
20
|
+
elasticipy-5.0.0.dist-info/METADATA,sha256=rAC-LNfE6PDiwgm3pTj-pfHwN7qYOSiO9dwcqINlQoE,5641
|
|
21
|
+
elasticipy-5.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
elasticipy-5.0.0.dist-info/entry_points.txt,sha256=_qorlXlBN9qlzrZfxQ1pSuUubadTEQXmUfQAzv8e9DE,74
|
|
23
|
+
elasticipy-5.0.0.dist-info/top_level.txt,sha256=k4zSQzJR5P4vzlHlhWUaxNgvgloq4KIp8oca2X8gQOw,11
|
|
24
|
+
elasticipy-5.0.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Elasticipy/FourthOrderTensor.py,sha256=jKXGD69Zas5CKQfeSz-AgLfeYX2XN-O6Q6lGtBKuoiU,508
|
|
2
|
-
Elasticipy/StressStrainTensors.py,sha256=xs4wgG1ohx3pT-X5GZUlm511SazHPsD_-okn822NqCA,491
|
|
3
|
-
Elasticipy/ThermalExpansion.py,sha256=O7VlU_8prjUzlVhQ4N-J66Zhs89S7TqllepUOQ-psJM,411
|
|
4
|
-
Elasticipy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
Elasticipy/crystal_symmetries.py,sha256=DAX-XPgYqI2nFvf6anCVvZ5fLM0CNSDJ7r2h15l3Hoc,3958
|
|
6
|
-
Elasticipy/gui.py,sha256=-YyaM09EcD9xHxtnq8bqVus9gXYlBNFyaysJ-BKhxYo,11248
|
|
7
|
-
Elasticipy/plasticity.py,sha256=-6j22R9rb6Ox-CtrzSRLxOdjk38pfqOeNHN-AaY9GCM,12255
|
|
8
|
-
Elasticipy/polefigure.py,sha256=-Qrf5B4_m8HSlwXfOntie75EUqKnFsl7ZeXx9lNPUsY,4119
|
|
9
|
-
Elasticipy/spherical_function.py,sha256=Mnb4Cj2eyMCtr7X3mesqESml3BMA_JYT2H3eTZO-AVk,40958
|
|
10
|
-
Elasticipy/interfaces/FEPX.py,sha256=MleuKz3JvjhvECIcg2q1taV0J1TzoiTrrtLeRRYI9Hs,4234
|
|
11
|
-
Elasticipy/interfaces/PRISMS.py,sha256=jAHFS2ybbAK2ZcqF9AmnlDTR2JZZMwlgy-FhQIINSAI,3835
|
|
12
|
-
Elasticipy/tensors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
Elasticipy/tensors/elasticity.py,sha256=vgpPA1FkehKuvSnPq4KEvddXpPgka1wGsp3AdjAdMB8,65000
|
|
14
|
-
Elasticipy/tensors/fourth_order.py,sha256=ouptzPiWx5W6t9dYWfLY8lTVTj5ahnuB4mmBUIgLycs,23136
|
|
15
|
-
Elasticipy/tensors/mapping.py,sha256=f-jwvCE2V3bgesIOyeC-vgqVCFJetlUviEAoaBE7yPA,1442
|
|
16
|
-
Elasticipy/tensors/second_order.py,sha256=6jQiIfGgmW7OsBvhPEXeRXjIcuslqejFHmGjHdYaMsQ,55728
|
|
17
|
-
Elasticipy/tensors/stress_strain.py,sha256=RysKDHe-PV2dpdrO7cNT1_UBP8bYYCbWxz3H9w9GuPo,3954
|
|
18
|
-
Elasticipy/tensors/thermal_expansion.py,sha256=XZ9e8Sn9vsLGVh79TrBQoBOkXMg8qF3pShiPSzix4q0,8634
|
|
19
|
-
elasticipy-4.1.1.dist-info/licenses/LICENSE,sha256=qNthTMSjVkIDM1_BREgVFQHdn1wVNQi9pwWVfTIazMA,1074
|
|
20
|
-
elasticipy-4.1.1.dist-info/METADATA,sha256=3OJs1eydCV7Q_L-vQd57Q1c1x-CmSRst4L5S4QYZKF4,4487
|
|
21
|
-
elasticipy-4.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
-
elasticipy-4.1.1.dist-info/top_level.txt,sha256=k4zSQzJR5P4vzlHlhWUaxNgvgloq4KIp8oca2X8gQOw,11
|
|
23
|
-
elasticipy-4.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|