Elaston 0.0.2__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,12 @@
1
+ *.pyc
2
+ .DS_Store
3
+ .coverage
4
+ nohup.out
5
+ pyiron.log
6
+ .idea/
7
+ inspectionProfiles/
8
+ _build/
9
+ apidoc/
10
+ .ipynb_checkpoints/
11
+ test_times.dat
12
+ core.*
elaston-0.0.2/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Max-Planck-Institut für Nachhaltige Materialien GmbH - Computational Materials Design (CM) Department
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
elaston-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: Elaston
3
+ Version: 0.0.2
4
+ Summary: Elaston - linear elasticity toolbox
5
+ Project-URL: Homepage, https://pyiron.org/
6
+ Project-URL: Documentation, https://elaston.readthedocs.io
7
+ Project-URL: Repository, https://github.com/pyiron/elaston
8
+ Author-email: Sam Waseda <waseda@mpie.de>
9
+ License: BSD 3-Clause License
10
+
11
+ Copyright (c) 2024, Max-Planck-Institut für Nachhaltige Materialien GmbH - Computational Materials Design (CM) Department
12
+ All rights reserved.
13
+
14
+ Redistribution and use in source and binary forms, with or without
15
+ modification, are permitted provided that the following conditions are met:
16
+
17
+ * Redistributions of source code must retain the above copyright notice, this
18
+ list of conditions and the following disclaimer.
19
+
20
+ * Redistributions in binary form must reproduce the above copyright notice,
21
+ this list of conditions and the following disclaimer in the documentation
22
+ and/or other materials provided with the distribution.
23
+
24
+ * Neither the name of the copyright holder nor the names of its
25
+ contributors may be used to endorse or promote products derived from
26
+ this software without specific prior written permission.
27
+
28
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
32
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
+ License-File: LICENSE
39
+ Keywords: pyiron
40
+ Classifier: Development Status :: 3 - Alpha
41
+ Classifier: Intended Audience :: Science/Research
42
+ Classifier: License :: OSI Approved :: BSD License
43
+ Classifier: Operating System :: OS Independent
44
+ Classifier: Programming Language :: Python :: 3.11
45
+ Classifier: Programming Language :: Python :: 3.12
46
+ Classifier: Programming Language :: Python :: 3.13
47
+ Classifier: Programming Language :: Python :: 3.14
48
+ Classifier: Topic :: Scientific/Engineering
49
+ Requires-Python: <3.15,>=3.11
50
+ Requires-Dist: numpy<2.5.0,>=2.4.6
51
+ Requires-Dist: semantikon<1.4.0,>=1.3.2
52
+ Description-Content-Type: text/markdown
53
+
54
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pyiron/elaston/HEAD)
55
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
56
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4aaeaca43ca54789ae5b328e17e1d937)](https://app.codacy.com/gh/pyiron/elaston/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
57
+ [![Coverage Status](https://coveralls.io/repos/github/pyiron/elaston/badge.svg?branch=main)](https://coveralls.io/github/pyiron/elaston?branch=main)
58
+ [![Documentation Status](https://readthedocs.org/projects/elaston/badge/?version=latest)](https://elaston.readthedocs.io/en/latest/?badge=latest)
59
+
60
+ # Elaston
61
+
62
+ Elaston is a simple and lightweight module for linear elasticity calculations.
63
+
64
+ ## Installation
65
+
66
+ We will offer pip and conda at some point. For now, you can install the package by cloning the repository and running the following command in the root directory:
67
+
68
+ ```bash
69
+ pip install .
70
+ ```
71
+
72
+ ## Features
73
+
74
+ - Calculation of elastic constants
75
+ - Stress, strain and displacement field around dislocations using anisotropic elasticity
76
+ - Stress, strain and displacement field around point defects
77
+
78
+
79
+ ## Usage
80
+
81
+ Examples I: Get bulk modulus from the elastic tensor:
82
+
83
+ ```python
84
+ from elaston import LinearElasticity
85
+
86
+ medium = LinearElasticity(C_11=211.0, C_12=130.0, C_44=82.0) # Fe
87
+ medium_voigt = medium.get_voigt_average()
88
+ parameters = medium_voigt.get_elastic_moduli()
89
+ print(parameters['bulk_modulus'])
90
+ ```
91
+
92
+
93
+ Example II: Get strain field around a point defect:
94
+
95
+ ```python
96
+ import numpy as np
97
+ medium = LinearElasticity(C_11=211.0, C_12=130.0, C_44=82.0)
98
+ random_positions = np.random.random((10, 3)) - 0.5
99
+ dipole_tensor = np.eye(3)
100
+ print(medium.get_point_defect_strain(random_positions, dipole_tensor))
101
+ ```
102
+
103
+
104
+ Example III: Get stress field around a dislocation:
105
+
106
+ ```python
107
+ import numpy as np
108
+ medium = LinearElasticity(C_11=211.0, C_12=130.0, C_44=82.0)
109
+ random_positions = np.random.random((10, 3)) - 0.5
110
+ # Burgers vector of a screw dislocation in bcc Fe
111
+ burgers_vector = np.array([0, 0, 2.86 * np.sqrt(3) / 2])
112
+ print(medium.get_dislocation_stress(random_positions, burgers_vector))
113
+ ```
114
+
115
+ Example IV: Estimate the distance between partial dislocations:
116
+
117
+ ```python
118
+ medium = LinearElasticity(C_11=110.5, C_12=64.8, C_44=30.9) # Al
119
+ lattice_constant = 4.05
120
+ partial_one = np.array([-0.5, 0, np.sqrt(3) / 2]) * lattice_constant
121
+ partial_two = np.array([0.5, 0, np.sqrt(3) / 2]) * lattice_constant
122
+ distance = 100
123
+ stress_one = medium.get_dislocation_stress([0, distance, 0], partial_one)
124
+ print('Choose `distance` in the way that the value below corresponds to SFE')
125
+ medium.get_dislocation_force(stress_one, [0, 1, 0], partial_two)
126
+ ```
@@ -0,0 +1,13 @@
1
+ import importlib.metadata
2
+
3
+ try:
4
+ # Installed package will find its version
5
+ __version__ = importlib.metadata.version(__name__)
6
+ except importlib.metadata.PackageNotFoundError:
7
+ # Repository clones will register an unknown version
8
+ __version__ = "0.0.0+unknown"
9
+
10
+
11
+ from elaston.linear_elasticity import LinearElasticity
12
+
13
+ __all__ = ["LinearElasticity"]
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.0.2'
22
+ __version_tuple__ = version_tuple = (0, 0, 2)
23
+
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,292 @@
1
+ # coding: utf-8
2
+ # Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
3
+ # Distributed under the terms of "New BSD License", see the LICENSE file.
4
+
5
+ from functools import cached_property
6
+ from typing import Annotated
7
+
8
+ import numpy as np
9
+ from semantikon.converter import units
10
+
11
+ __author__ = "Sam Waseda"
12
+ __copyright__ = (
13
+ "Copyright 2021, Max-Planck-Institut für Eisenforschung GmbH "
14
+ "- Computational Materials Design (CM) Department"
15
+ )
16
+ __version__ = "1.0"
17
+ __maintainer__ = "Sam Waseda"
18
+ __email__ = "waseda@mpie.de"
19
+ __status__ = "development"
20
+ __date__ = "Aug 21, 2021"
21
+
22
+
23
+ class Dislocation:
24
+ """
25
+ Anisotropic elasticity theory for dislocations described by
26
+ [Eshelby](https://doi.org/10.1016/0001-6160(53)90099-6).
27
+
28
+ All notations follow the original paper.
29
+ """
30
+
31
+ def __init__(self, elastic_tensor: np.ndarray, burgers_vector: np.ndarray) -> None:
32
+ """
33
+ Args:
34
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
35
+ burgers_vector ((3,)-array): Burgers vector
36
+ """
37
+ assert np.shape(elastic_tensor) == (3, 3, 3, 3)
38
+ assert np.shape(burgers_vector) == (3,)
39
+ self.elastic_tensor = elastic_tensor
40
+ self.burgers_vector = burgers_vector
41
+ self.fit_range = np.linspace(0, 1, 10)
42
+
43
+ def _get_pmat(self, x: np.ndarray) -> np.ndarray:
44
+ return (
45
+ self.elastic_tensor[:, 0, :, 0]
46
+ + np.einsum(
47
+ "...,ij->...ij",
48
+ x,
49
+ self.elastic_tensor[:, 0, :, 1] + self.elastic_tensor[:, 1, :, 0],
50
+ )
51
+ + np.einsum("...,ij->...ij", x**2, self.elastic_tensor[:, 1, :, 1])
52
+ )
53
+
54
+ @cached_property
55
+ def p(self) -> np.ndarray:
56
+ coeff = np.polyfit(
57
+ self.fit_range, np.linalg.det(self._get_pmat(self.fit_range)), 6
58
+ )
59
+ p = np.roots(coeff)
60
+ p = p[np.imag(p) > 0]
61
+ return p
62
+
63
+ @cached_property
64
+ def Ak(self) -> np.ndarray:
65
+ Ak = []
66
+ for mat in self._get_pmat(self.p):
67
+ values, vectors = np.linalg.eig(mat.T)
68
+ Ak.append(vectors.T[np.absolute(values).argmin()])
69
+ return np.array(Ak)
70
+
71
+ @cached_property
72
+ def D(self) -> np.ndarray:
73
+ F = np.einsum("n,ij->nij", self.p, self.elastic_tensor[:, 1, :, 1])
74
+ F += self.elastic_tensor[:, 1, :, 0]
75
+ F = np.einsum("nik,nk->ni", F, self.Ak)
76
+ F = np.concatenate((F.T, self.Ak.T), axis=0)
77
+ F = np.concatenate((np.real(F), -np.imag(F)), axis=-1)
78
+ D = np.linalg.solve(F, np.concatenate((np.zeros(3), self.burgers_vector)))
79
+ return D[:3] + 1j * D[3:]
80
+
81
+ @property
82
+ def dzdx(self) -> np.ndarray:
83
+ return np.stack((np.ones_like(self.p), self.p, np.zeros_like(self.p)), axis=-1)
84
+
85
+ def _get_z(self, positions: np.ndarray) -> np.ndarray:
86
+ z = np.stack((np.ones_like(self.p), self.p), axis=-1)
87
+ return np.einsum("nk,...k->...n", z, np.asarray(positions)[..., :2])
88
+
89
+ def get_displacement(self, positions: np.ndarray) -> np.ndarray:
90
+ """
91
+ Displacement vectors
92
+
93
+ Args:
94
+ positions ((n,3)-array): Positions for which the displacements are
95
+ to be calculated
96
+
97
+ Returns:
98
+ ((n,3)-array): Displacement vectors
99
+ """
100
+ return np.imag(
101
+ np.einsum(
102
+ "nk,n,...n->...k", self.Ak, self.D, np.log(self._get_z(positions))
103
+ )
104
+ ) / (2 * np.pi)
105
+
106
+ def get_strain(self, positions: np.ndarray) -> np.ndarray:
107
+ """
108
+ Strain tensors
109
+
110
+ Args:
111
+ positions ((n,3)-array): Positions for which the strains are to be
112
+ calculated
113
+
114
+ Returns:
115
+ ((n,3,3)-array): Strain tensors
116
+ """
117
+ strain = np.imag(
118
+ np.einsum(
119
+ "ni,n,...n,nj->...ij",
120
+ self.Ak,
121
+ self.D,
122
+ 1 / self._get_z(positions),
123
+ self.dzdx,
124
+ )
125
+ )
126
+ strain = strain + np.einsum("...ij->...ji", strain)
127
+ return strain / 4 / np.pi
128
+
129
+
130
+ @units
131
+ def get_dislocation_displacement(
132
+ elastic_tensor: Annotated[np.ndarray, {"units": "=e"}],
133
+ positions: np.ndarray,
134
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
135
+ ) -> Annotated[np.ndarray, {"units": "=b"}]:
136
+ """
137
+ Displacement field around a dislocation according to anisotropic elasticity theory
138
+ described by [Eshelby](https://doi.org/10.1016/0001-6160(53)90099-6).
139
+
140
+ Args:
141
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
142
+ positions ((n,2) or (n,3)-array): Position around a dislocation. The third axis
143
+ coincides with the dislocation line.
144
+ burgers_vector ((3,)-array): Burgers vector
145
+
146
+ Returns:
147
+ ((n, 3)-array): Displacement field (z-axis coincides with the dislocation line)
148
+ """
149
+ return Dislocation(elastic_tensor, burgers_vector).get_displacement(positions)
150
+
151
+
152
+ @units
153
+ def get_dislocation_strain(
154
+ elastic_tensor: Annotated[np.ndarray, {"units": "=e"}],
155
+ positions: Annotated[np.ndarray, {"units": "=p"}],
156
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
157
+ ) -> Annotated[np.ndarray, {"units": "=b/p"}]:
158
+ """
159
+ Strain field around a dislocation according to anisotropic elasticity theory
160
+ described by [Eshelby](https://doi.org/10.1016/0001-6160(53)90099-6).
161
+
162
+ Args:
163
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
164
+ positions ((n,2) or (n,3)-array): Position around a dislocation. The third axis
165
+ coincides with the dislocation line.
166
+ burgers_vector ((3,)-array): Burgers vector
167
+
168
+ Returns:
169
+ ((n, 3, 3)-array): Strain field (z-axis coincides with the dislocation line)
170
+ """
171
+ return Dislocation(elastic_tensor, burgers_vector).get_strain(positions)
172
+
173
+
174
+ @units
175
+ def get_dislocation_stress(
176
+ elastic_tensor: Annotated[np.ndarray, {"units": "=e"}],
177
+ positions: Annotated[np.ndarray, {"units": "=p"}],
178
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
179
+ ) -> Annotated[np.ndarray, {"units": "=e*b/p"}]:
180
+ """
181
+ Stress field around a dislocation according to anisotropic elasticity theory
182
+ described by [Eshelby](https://doi.org/10.1016/0001-6160(53)90099-6).
183
+
184
+ Args:
185
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
186
+ positions ((n,2) or (n,3)-array): Position around a dislocation. The third axis
187
+ coincides with the dislocation line.
188
+ burgers_vector ((3,)-array): Burgers vector
189
+
190
+ Returns:
191
+ ((n, 3, 3)-array): Stress field (z-axis coincides with the dislocation line)
192
+ """
193
+ strain = get_dislocation_strain(elastic_tensor, positions, burgers_vector)
194
+ return np.einsum("ijkl,...kl->...ij", elastic_tensor, strain)
195
+
196
+
197
+ @units
198
+ def get_dislocation_energy_density(
199
+ elastic_tensor: Annotated[np.ndarray, {"units": "=e"}],
200
+ positions: Annotated[np.ndarray, {"units": "=p"}],
201
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
202
+ ) -> Annotated[np.ndarray, {"units": "=e*b**2/p**2"}]:
203
+ """
204
+ Energy density field around a dislocation (product of stress and strain, cf. corresponding
205
+ methods)
206
+
207
+ Args:
208
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
209
+ positions ((n,2) or (n,3)-array): Position around a dislocation. The third axis
210
+ coincides with the dislocation line.
211
+ burgers_vector ((3,)-array): Burgers vector
212
+
213
+ Returns:
214
+ ((n,)-array): Energy density field
215
+ """
216
+ strain = get_dislocation_strain(elastic_tensor, positions, burgers_vector)
217
+ return np.einsum("ijkl,...kl,...ij->...", elastic_tensor, strain, strain)
218
+
219
+
220
+ @units
221
+ def get_dislocation_energy(
222
+ elastic_tensor: Annotated[np.ndarray, {"units": "=e"}],
223
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
224
+ r_min: Annotated[float, {"units": "=r"}],
225
+ r_max: Annotated[float, {"units": "=r"}],
226
+ mesh: int = 100,
227
+ ) -> Annotated[float, {"units": "=e*b**2"}]:
228
+ """
229
+ Energy per unit length along the dislocation line.
230
+
231
+ Args:
232
+ elastic_tensor ((3,3,3,3)-array): Elastic tensor
233
+ burgers_vector ((3,)-array): Burgers vector
234
+ r_min (float): Minimum distance from the dislocation core
235
+ r_max (float): Maximum distance from the dislocation core
236
+ mesh (int): Number of grid points for the numerical integration along the angle
237
+
238
+ Returns:
239
+ (float): Energy of dislocation per unit length
240
+
241
+ The energy is defined by the product of the stress and strain (i.e. energy density),
242
+ which is integrated over the plane vertical to the dislocation line. The energy density
243
+ :math:`w` according to the linear elasticity is given by:
244
+
245
+ .. math:
246
+ w(r, \\theta) = A(\\theta)/r^2
247
+
248
+ Therefore, the energy per unit length :math:`U` is given by:
249
+
250
+ .. math:
251
+ U = \\log(r_max/r_min)\\int A(\\theta)\\mathrm d\\theta
252
+
253
+ This implies :math:`r_min` cannot be 0 as well as :math:`r_max` cannot be infinity. This
254
+ is the consequence of the fact that the linear elasticity cannot describe the core
255
+ structure properly, and a real medium is not infinitely large. While :math:`r_max` can
256
+ be defined based on the real dislocation density, the choice of :math:`r_min` should be
257
+ done carefully.
258
+ """
259
+ if r_min <= 0:
260
+ raise ValueError("r_min must be a positive float")
261
+ theta_range = np.linspace(0, 2 * np.pi, 100, endpoint=False)
262
+ r = np.stack((np.cos(theta_range), np.sin(theta_range)), axis=-1) * r_min
263
+ strain = get_dislocation_strain(elastic_tensor, r, burgers_vector=burgers_vector)
264
+ return (
265
+ np.einsum("ijkl,nkl,nij->", elastic_tensor, strain, strain)
266
+ * np.diff(theta_range)[0]
267
+ * r_min**2
268
+ * np.log(r_max / r_min)
269
+ )
270
+
271
+
272
+ @units
273
+ def get_dislocation_force(
274
+ stress: Annotated[np.ndarray, {"units": "=s"}],
275
+ glide_plane: np.ndarray,
276
+ burgers_vector: Annotated[np.ndarray, {"units": "=b"}],
277
+ ) -> Annotated[np.ndarray, {"units": "=s*b"}]:
278
+ """
279
+ Force per unit length along the dislocation line.
280
+
281
+ Args:
282
+ stress ((n, 3, 3)-array): External stress field at the dislocation line
283
+ glide_plane ((3,)-array): Glide plane
284
+ burgers_vector ((3,)-array): Burgers vector
285
+
286
+ Returns:
287
+ ((3,)-array): Force per unit length acting on the dislocation.
288
+ """
289
+ g = np.asarray(glide_plane) / np.linalg.norm(glide_plane)
290
+ return np.einsum(
291
+ "i,...ij,j,k->...k", g, stress, burgers_vector, np.cross(g, [0, 0, 1])
292
+ )