EasyFEA 1.2.2__tar.gz → 1.2.4__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.
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Simulations.py +1 -1
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_gmsh_interface.py +8 -4
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_elastic.py +70 -2
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_phasefield.py +31 -22
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_dic.py +2 -2
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_phasefield.py +10 -10
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_utils.py +40 -3
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Display.py +3 -3
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Folder.py +4 -6
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/PyVista_Interface.py +24 -12
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/PKG-INFO +1 -1
- {easyfea-1.2.2 → easyfea-1.2.4}/PKG-INFO +1 -1
- {easyfea-1.2.2 → easyfea-1.2.4}/pyproject.toml +1 -1
- {easyfea-1.2.2 → easyfea-1.2.4}/AUTHORS.md +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Geoms.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Materials.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/__about__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_boundary_conditions.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_gauss.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_group_elems.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_mesh.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_utils.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_hexa.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_point.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_prism.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_quad.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_seg.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_tetra.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_tri.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_beam.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_thermal.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_utils.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/Solvers.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_beam.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_elastic.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_simu.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_thermal.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Numba_Interface.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Paraview_Interface.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/__init__.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/_observers.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/_tic.py +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/SOURCES.txt +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/dependency_links.txt +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/requires.txt +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/top_level.txt +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/LICENSE.txt +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/README.md +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/setup.cfg +0 -0
- {easyfea-1.2.2 → easyfea-1.2.4}/setup.py +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"""This module contains all available simulation classes."""
|
|
6
6
|
|
|
7
7
|
from .simulations._simu import _Simu, Load_Simu
|
|
8
|
-
from .simulations._utils import Save_Force_Displacement, Load_Force_Displacement
|
|
8
|
+
from .simulations._utils import Save_Force_Displacement, Load_Force_Displacement, Save_pickle, Load_pickle
|
|
9
9
|
|
|
10
10
|
# ----------------------------------------------
|
|
11
11
|
# Elastic
|
|
@@ -441,7 +441,7 @@ class Mesher:
|
|
|
441
441
|
p1 = factory.addPoint(*line.pt1.coord, line.meshSize) # start
|
|
442
442
|
p2 = factory.addPoint(*line.pt2.coord, line.meshSize) # end
|
|
443
443
|
p3 = factory.addPoint(*line.pt3.coord, line.meshSize) # mid
|
|
444
|
-
geom_line = factory.addCircleArc(p1, p3, p2)
|
|
444
|
+
geom_line = factory.addCircleArc(p1, p3, p2, center=False)
|
|
445
445
|
else:
|
|
446
446
|
raise Exception("You need to give lines or arcs.")
|
|
447
447
|
factory.fragment(ents, [(1, geom_line)], removeTool=False)
|
|
@@ -879,6 +879,7 @@ class Mesher:
|
|
|
879
879
|
elif isinstance(crack, Contour): # 2D CRACK
|
|
880
880
|
|
|
881
881
|
loop, lines, points, openLns, openPts = self._Loop_From_Contour(crack)
|
|
882
|
+
|
|
882
883
|
try:
|
|
883
884
|
surf = self._Surface_From_Loops([loop])
|
|
884
885
|
except Exception:
|
|
@@ -925,7 +926,7 @@ class Mesher:
|
|
|
925
926
|
newEntities.extend([(2, surf) for surf in entities2D])
|
|
926
927
|
|
|
927
928
|
if factory == gmsh.model.occ:
|
|
928
|
-
o, m = gmsh.model.occ.fragment(entities, newEntities)
|
|
929
|
+
o, m = gmsh.model.occ.fragment(entities, newEntities, removeTool=False)
|
|
929
930
|
|
|
930
931
|
self._Synchronize() # mandatory
|
|
931
932
|
|
|
@@ -1315,6 +1316,8 @@ class Mesher:
|
|
|
1315
1316
|
Geometric objects to refine de background mesh
|
|
1316
1317
|
meshSize : float
|
|
1317
1318
|
size of elements outside the domain
|
|
1319
|
+
extrude : list[float]
|
|
1320
|
+
extrusion vector, by default [0,0,1]
|
|
1318
1321
|
"""
|
|
1319
1322
|
|
|
1320
1323
|
# See t10.py in the gmsh tutorials
|
|
@@ -1323,8 +1326,8 @@ class Mesher:
|
|
|
1323
1326
|
assert isinstance(refineGeoms, Iterable), "refineGeoms must be a list of geometric objects."
|
|
1324
1327
|
|
|
1325
1328
|
if refineGeoms is None or len(refineGeoms) == 0: return
|
|
1326
|
-
|
|
1327
|
-
fields =
|
|
1329
|
+
|
|
1330
|
+
fields = list(gmsh.model.mesh.field.list())
|
|
1328
1331
|
|
|
1329
1332
|
for geom in refineGeoms:
|
|
1330
1333
|
|
|
@@ -1466,6 +1469,7 @@ class Mesher:
|
|
|
1466
1469
|
"""
|
|
1467
1470
|
|
|
1468
1471
|
self._Set_mesh_algorithm(elemType)
|
|
1472
|
+
# self._factory.removeAllDuplicates()
|
|
1469
1473
|
self._Synchronize() # mandatory
|
|
1470
1474
|
|
|
1471
1475
|
tic = Tic()
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from typing import Union
|
|
7
|
+
from scipy.linalg import sqrtm
|
|
7
8
|
|
|
8
9
|
# utilities
|
|
9
10
|
from .. import np
|
|
@@ -106,6 +107,7 @@ class _Elas(_IModel, ABC):
|
|
|
106
107
|
shape = (3, 3) if self.dim == 2 else (6, 6)
|
|
107
108
|
assert array.shape[-2:] == shape, f"With dim = {self.dim} array must be a {shape} matrix"
|
|
108
109
|
self.__C = array
|
|
110
|
+
self.__sqrt_C = None # dont remove
|
|
109
111
|
|
|
110
112
|
@property
|
|
111
113
|
def isHeterogeneous(self) -> bool:
|
|
@@ -129,6 +131,7 @@ class _Elas(_IModel, ABC):
|
|
|
129
131
|
shape = (3, 3) if self.dim == 2 else (6, 6)
|
|
130
132
|
assert array.shape[-2:] == shape, f"With dim = {self.dim} array must be a {shape} matrix"
|
|
131
133
|
self.__S = array
|
|
134
|
+
self.__sqrt_S = None # dont remove
|
|
132
135
|
|
|
133
136
|
@abstractmethod
|
|
134
137
|
def Walpole_Decomposition(self) -> tuple[np.ndarray, np.ndarray]:
|
|
@@ -136,6 +139,62 @@ class _Elas(_IModel, ABC):
|
|
|
136
139
|
C = sum(ci * Ei).\n
|
|
137
140
|
returns ci, Ei"""
|
|
138
141
|
return np.array([]), np.array([])
|
|
142
|
+
|
|
143
|
+
def Get_sqrt_C_S(self) -> tuple[np.ndarray, np.ndarray]:
|
|
144
|
+
"""Returns the Matrix square root of C and S."""
|
|
145
|
+
|
|
146
|
+
C = self.C
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
self.__sqrt_C is None
|
|
150
|
+
self.__sqrt_S is None
|
|
151
|
+
except AttributeError:
|
|
152
|
+
# init
|
|
153
|
+
self.__sqrt_C = None
|
|
154
|
+
self.__sqrt_S = None
|
|
155
|
+
|
|
156
|
+
if self.__sqrt_C is None:
|
|
157
|
+
|
|
158
|
+
if self.isHeterogeneous:
|
|
159
|
+
|
|
160
|
+
shape = C.shape
|
|
161
|
+
|
|
162
|
+
assert len(shape) == 3, "This function is not currently implemented for heterogeneous matrices where material properties are defined on Gauss points."
|
|
163
|
+
|
|
164
|
+
uniq_C, inverse = np.unique(C, return_inverse=True, axis=0)
|
|
165
|
+
|
|
166
|
+
sqrtC = np.zeros_like(C, dtype=float)
|
|
167
|
+
sqrtS = np.zeros_like(C, dtype=float)
|
|
168
|
+
|
|
169
|
+
for i, C in enumerate(uniq_C):
|
|
170
|
+
|
|
171
|
+
elems = np.where(inverse == i)[0]
|
|
172
|
+
|
|
173
|
+
sqrtmC = sqrtm(C)
|
|
174
|
+
sqrtC[elems] = sqrtmC
|
|
175
|
+
|
|
176
|
+
sqrtmS = np.linalg.inv(sqrtmC)
|
|
177
|
+
sqrtS[elems] = sqrtmS
|
|
178
|
+
|
|
179
|
+
else:
|
|
180
|
+
sqrtC = sqrtm(C)
|
|
181
|
+
|
|
182
|
+
sqrtS = np.linalg.inv(sqrtC) # faster than sqrtm(self.S)
|
|
183
|
+
# sqrtS = sqrtm(self.S)
|
|
184
|
+
|
|
185
|
+
# # give the same results !!!
|
|
186
|
+
# test = np.linalg.norm(sqrtS - sqrtm(self.S))/np.linalg.norm(sqrtS)
|
|
187
|
+
# assert test < 1e-12
|
|
188
|
+
|
|
189
|
+
self.__sqrt_C = sqrtC
|
|
190
|
+
self.__sqrt_S = sqrtS
|
|
191
|
+
|
|
192
|
+
else:
|
|
193
|
+
|
|
194
|
+
sqrtC = self.__sqrt_C.copy()
|
|
195
|
+
sqrtS = self.__sqrt_S.copy()
|
|
196
|
+
|
|
197
|
+
return sqrtC, sqrtS
|
|
139
198
|
|
|
140
199
|
# ----------------------------------------------
|
|
141
200
|
# Isotropic
|
|
@@ -747,8 +806,17 @@ class Elas_Anisot(_Elas):
|
|
|
747
806
|
shape = C.shape
|
|
748
807
|
assert (shape[-2], shape[-1]) in [(3,3), (6,6)], 'C must be a (3,3) or (6,6) matrix'
|
|
749
808
|
dim = 3 if C.shape[-1] == 6 else 2
|
|
750
|
-
|
|
751
|
-
|
|
809
|
+
if len(C.shape) == 2:
|
|
810
|
+
Ct = C.T
|
|
811
|
+
elif len(C.shape) == 3:
|
|
812
|
+
Ct = np.transpose(C, (0,2,1))
|
|
813
|
+
elif len(C.shape) == 4:
|
|
814
|
+
Ct = np.transpose(C, (0,1,3,2))
|
|
815
|
+
else:
|
|
816
|
+
raise ValueError("This matrix must be of dimensions (dim, dim), (Ne, dim, dim) or (Ne, nPg, dim, dim).")
|
|
817
|
+
|
|
818
|
+
testSym = np.linalg.norm(Ct - C, axis=(-2, -1))/np.linalg.norm(C, axis=(-2, -1))
|
|
819
|
+
assert np.max(testSym) <= 1e-12, "The matrix is not symmetrical."
|
|
752
820
|
|
|
753
821
|
if useVoigtNotation:
|
|
754
822
|
C_mandel = KelvinMandel_Matrix(dim, C)
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
from typing import Union
|
|
6
6
|
from enum import Enum
|
|
7
7
|
|
|
8
|
-
from scipy.linalg import sqrtm
|
|
9
|
-
|
|
10
8
|
# utilities
|
|
11
9
|
from .. import np
|
|
12
10
|
from ..utilities import Tic, Numba_Interface
|
|
@@ -737,22 +735,28 @@ class PhaseField(_IModel):
|
|
|
737
735
|
# Here the material is supposed to be homogeneous
|
|
738
736
|
material = self.__material
|
|
739
737
|
|
|
740
|
-
C = material.C
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
#
|
|
745
|
-
|
|
738
|
+
C = material.C
|
|
739
|
+
|
|
740
|
+
tic = Tic()
|
|
741
|
+
sqrtC, inv_sqrtC = material.Get_sqrt_C_S()
|
|
742
|
+
# inv(sqrtC) = sqrtS
|
|
743
|
+
tic.Tac("Split",f"sqrt C and S", False)
|
|
746
744
|
|
|
747
|
-
if verif
|
|
745
|
+
if verif:
|
|
748
746
|
# checks that C^1/2 * C^1/2 = C
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
inv_sqrtC = np.linalg.inv(sqrtC)
|
|
747
|
+
diff_C = sqrtC @ sqrtC - C
|
|
748
|
+
test_C = np.linalg.norm(diff_C, axis=(-2,-1))/np.linalg.norm(C, axis=(-2,-1))
|
|
749
|
+
assert np.max(test_C) < 1e-12
|
|
753
750
|
|
|
754
751
|
# computes new "strain" field
|
|
755
|
-
|
|
752
|
+
|
|
753
|
+
ind = ""
|
|
754
|
+
if len(C.shape) == 3:
|
|
755
|
+
ind = 'e'
|
|
756
|
+
elif len(C.shape) == 4:
|
|
757
|
+
ind = 'ep'
|
|
758
|
+
|
|
759
|
+
Epsilont_e_pg = np.einsum(f'{ind}ij,epj->epi', sqrtC, Epsilon_e_pg, optimize='optimal')
|
|
756
760
|
|
|
757
761
|
# Computes projectors
|
|
758
762
|
projPt_e_pg, projMt_e_pg = self.__Spectral_Decomposition(Epsilont_e_pg, verif)
|
|
@@ -763,18 +767,23 @@ class PhaseField(_IModel):
|
|
|
763
767
|
# projM_e_pg = inv_sqrtC @ (projMt_e_pg @ sqrtC)
|
|
764
768
|
|
|
765
769
|
# faster
|
|
766
|
-
projP_e_pg = np.einsum('ij,epjk,kl->epil', inv_sqrtC, projPt_e_pg, sqrtC, optimize='optimal')
|
|
767
|
-
projM_e_pg = np.einsum('ij,epjk,kl->epil', inv_sqrtC, projMt_e_pg, sqrtC, optimize='optimal')
|
|
770
|
+
projP_e_pg = np.einsum(f'{ind}ij,epjk,{ind}kl->epil', inv_sqrtC, projPt_e_pg, sqrtC, optimize='optimal')
|
|
771
|
+
projM_e_pg = np.einsum(f'{ind}ij,epjk,{ind}kl->epil', inv_sqrtC, projMt_e_pg, sqrtC, optimize='optimal')
|
|
768
772
|
|
|
769
773
|
tic.Tac("Split",f"proj Tild to proj", False)
|
|
770
774
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
+
if material.isHeterogeneous:
|
|
776
|
+
cP_e_pg = np.einsum(f'{ind}ij,epjk->epik', C, projP_e_pg, optimize='optimal')
|
|
777
|
+
cM_e_pg = np.einsum(f'{ind}ij,epjk->epik', C, projM_e_pg, optimize='optimal')
|
|
778
|
+
|
|
779
|
+
else:
|
|
780
|
+
# cP_e_pg = sqrtC @ (projPt_e_pg @ sqrtC)
|
|
781
|
+
# cM_e_pg = sqrtC @ (projMt_e_pg @ sqrtC)
|
|
782
|
+
cP_e_pg = C @ projP_e_pg
|
|
783
|
+
cM_e_pg = C @ projM_e_pg
|
|
775
784
|
|
|
776
|
-
|
|
777
|
-
|
|
785
|
+
# test_cP = sqrtC @ (projPt_e_pg @ sqrtC) - C @ projP_e_pg
|
|
786
|
+
# test_cP = sqrtC @ (projMt_e_pg @ sqrtC) - C @ projM_e_pg
|
|
778
787
|
|
|
779
788
|
tic.Tac("Split",f"cP_e_pg and cM_e_pg", False)
|
|
780
789
|
|
|
@@ -189,12 +189,12 @@ class DIC(_IObserver):
|
|
|
189
189
|
tic.Tac("DIC", "ROI", self._verbosity)
|
|
190
190
|
|
|
191
191
|
@property
|
|
192
|
-
def roi(self) -> np.ndarray
|
|
192
|
+
def roi(self) -> np.ndarray:
|
|
193
193
|
"""roi as a vector."""
|
|
194
194
|
return self.__roi.copy()
|
|
195
195
|
|
|
196
196
|
@property
|
|
197
|
-
def ROI(self) -> np.ndarray
|
|
197
|
+
def ROI(self) -> np.ndarray:
|
|
198
198
|
"""roi as a matrix."""
|
|
199
199
|
return self.roi.reshape(self.shape)
|
|
200
200
|
|
|
@@ -210,12 +210,12 @@ class PhaseFieldSimu(_Simu):
|
|
|
210
210
|
Returns
|
|
211
211
|
-------
|
|
212
212
|
np.ndarray, np.ndarray, csr_matrix, bool
|
|
213
|
-
u_np1, d_np1,
|
|
213
|
+
u_np1, d_np1, Ku, converged
|
|
214
214
|
|
|
215
215
|
such that:\n
|
|
216
216
|
- u_np1: displacement vector field\n
|
|
217
217
|
- d_np1: damage scalar field\n
|
|
218
|
-
-
|
|
218
|
+
- Ku: displacement stiffness matrix\n
|
|
219
219
|
- converged: the solution has converged\n
|
|
220
220
|
"""
|
|
221
221
|
|
|
@@ -311,9 +311,9 @@ class PhaseFieldSimu(_Simu):
|
|
|
311
311
|
self.__convIter = convIter
|
|
312
312
|
self.__timeIter = timeIter
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
Ku = self.__Ku.copy()
|
|
315
315
|
|
|
316
|
-
return u_np1, d_np1,
|
|
316
|
+
return u_np1, d_np1, Ku, converged
|
|
317
317
|
|
|
318
318
|
# ------------------------------------------- Elastic problem -------------------------------------------
|
|
319
319
|
|
|
@@ -509,7 +509,7 @@ class PhaseFieldSimu(_Simu):
|
|
|
509
509
|
# Calculating elementary matrix
|
|
510
510
|
Kd_e, Fd_e = self.__Construct_Damage_Matrix()
|
|
511
511
|
|
|
512
|
-
#
|
|
512
|
+
# Assembly
|
|
513
513
|
tic = Tic()
|
|
514
514
|
|
|
515
515
|
self.__Kd = sparse.csr_matrix((Kd_e.ravel(), (linesScalar_e, columnsScalar_e)), shape = (Ndof, Ndof))
|
|
@@ -669,16 +669,16 @@ class PhaseFieldSimu(_Simu):
|
|
|
669
669
|
|
|
670
670
|
return self.Results_Reshape_values(values, nodeValues)
|
|
671
671
|
|
|
672
|
-
def __indexResult(self,
|
|
672
|
+
def __indexResult(self, result: str) -> int:
|
|
673
673
|
|
|
674
674
|
dim = self.dim
|
|
675
675
|
|
|
676
|
-
if len(
|
|
677
|
-
if "x" in
|
|
676
|
+
if len(result) <= 2:
|
|
677
|
+
if "x" in result:
|
|
678
678
|
return 0
|
|
679
|
-
elif "y" in
|
|
679
|
+
elif "y" in result:
|
|
680
680
|
return 1
|
|
681
|
-
elif "z" in
|
|
681
|
+
elif "z" in result:
|
|
682
682
|
return 1
|
|
683
683
|
|
|
684
684
|
def _Calc_Psi_Elas(self) -> float:
|
|
@@ -12,7 +12,7 @@ import pickle
|
|
|
12
12
|
# ----------------------------------------------
|
|
13
13
|
|
|
14
14
|
def Save_Force_Displacement(force: np.ndarray, displacement: np.ndarray, folder:str):
|
|
15
|
-
"""
|
|
15
|
+
"""Saves the values of force and displacement in the folder"""
|
|
16
16
|
|
|
17
17
|
folder_PythonEF = Folder.Get_Path(Folder.Get_Path())
|
|
18
18
|
filename = Folder.Join(folder, "force-displacement.pickle")
|
|
@@ -31,7 +31,7 @@ def Save_Force_Displacement(force: np.ndarray, displacement: np.ndarray, folder:
|
|
|
31
31
|
Display.MyPrint(f'Saved:\n{filename.replace(folder_PythonEF,"")}\n','green')
|
|
32
32
|
|
|
33
33
|
def Load_Force_Displacement(folder:str):
|
|
34
|
-
"""Loads
|
|
34
|
+
"""Loads force and displacement.
|
|
35
35
|
|
|
36
36
|
Parameters
|
|
37
37
|
----------
|
|
@@ -56,4 +56,41 @@ def Load_Force_Displacement(folder:str):
|
|
|
56
56
|
|
|
57
57
|
Display.MyPrint(f'Loaded:\n{shortName}\n','green')
|
|
58
58
|
|
|
59
|
-
return force, displacement
|
|
59
|
+
return force, displacement
|
|
60
|
+
|
|
61
|
+
# ----------------------------------------------
|
|
62
|
+
# Save obj in pickle file
|
|
63
|
+
# ----------------------------------------------
|
|
64
|
+
|
|
65
|
+
def Save_pickle(obj, folder: str, filename: str) -> None:
|
|
66
|
+
"""Saves the object in folder/filename.pickle."""
|
|
67
|
+
|
|
68
|
+
folder_PythonEF = Folder.Get_Path(Folder.Get_Path())
|
|
69
|
+
|
|
70
|
+
file = Folder.Join(folder, f"{filename}.pickle")
|
|
71
|
+
|
|
72
|
+
if not Folder.os.path.exists(folder):
|
|
73
|
+
Folder.os.makedirs(folder)
|
|
74
|
+
|
|
75
|
+
with open(file, "wb") as f:
|
|
76
|
+
pickle.dump(obj, f)
|
|
77
|
+
|
|
78
|
+
Display.MyPrint(f'Saved:\n{file.replace(folder_PythonEF,"")}\n','green')
|
|
79
|
+
|
|
80
|
+
def Load_pickle(folder:str, filename: str):
|
|
81
|
+
"""Returns folder/filename.pickle object."""
|
|
82
|
+
|
|
83
|
+
folder_PythonEF = Folder.Get_Path(Folder.Get_Path())
|
|
84
|
+
|
|
85
|
+
file = Folder.Join(folder, f"{filename}.pickle")
|
|
86
|
+
|
|
87
|
+
shortName = file.replace(folder_PythonEF,'')
|
|
88
|
+
error = f"{shortName} does not exist"
|
|
89
|
+
assert Folder.Exists(file), error
|
|
90
|
+
|
|
91
|
+
with open(file, 'rb') as f:
|
|
92
|
+
obj = pickle.load(f)
|
|
93
|
+
|
|
94
|
+
Display.MyPrint(f'Loaded:\n{shortName}\n','green')
|
|
95
|
+
|
|
96
|
+
return obj
|
|
@@ -43,7 +43,7 @@ def Plot_Result(obj, result: Union[str,np.ndarray], deformFactor=0.0, coef=1.0,
|
|
|
43
43
|
object containing the mesh
|
|
44
44
|
result : str or np.ndarray
|
|
45
45
|
result you want to display.\n
|
|
46
|
-
Must be included in simu.Get_Results() or be a numpy array of size of (
|
|
46
|
+
Must be included in simu.Get_Results() or be a numpy array of size of (Nn, Ne).
|
|
47
47
|
deformFactor : float, optional
|
|
48
48
|
factor used to display the deformed solution (0 means no deformations), default 0.0
|
|
49
49
|
coef : float, optional
|
|
@@ -133,7 +133,7 @@ def Plot_Result(obj, result: Union[str,np.ndarray], deformFactor=0.0, coef=1.0,
|
|
|
133
133
|
levels = np.linspace(min, max, ncolors)
|
|
134
134
|
|
|
135
135
|
if ncolors != 256:
|
|
136
|
-
norm = colors.BoundaryNorm(boundaries=
|
|
136
|
+
norm = colors.BoundaryNorm(boundaries=levels, ncolors=256)
|
|
137
137
|
else:
|
|
138
138
|
norm = None
|
|
139
139
|
|
|
@@ -178,7 +178,7 @@ def Plot_Result(obj, result: Union[str,np.ndarray], deformFactor=0.0, coef=1.0,
|
|
|
178
178
|
pc.set_clim(min, max)
|
|
179
179
|
pc.set_array(values)
|
|
180
180
|
ax.add_collection(pc)
|
|
181
|
-
ticks = None if ncolors != 11 else ticks
|
|
181
|
+
# ticks = None if ncolors != 11 else ticks
|
|
182
182
|
|
|
183
183
|
# Plots node values
|
|
184
184
|
elif mesh.Nn == len(values):
|
|
@@ -104,7 +104,10 @@ def PhaseField_Folder(folder: str, material: str,
|
|
|
104
104
|
|
|
105
105
|
if nL != 0:
|
|
106
106
|
assert nL > 0
|
|
107
|
-
|
|
107
|
+
if isinstance(nL, float):
|
|
108
|
+
name = f"{name} nL={nL:.2f}"
|
|
109
|
+
else:
|
|
110
|
+
name = f"{name} nL={nL}"
|
|
108
111
|
|
|
109
112
|
workFolder = New_File(folder, results=True)
|
|
110
113
|
path = workFolder.split(folder)[0]
|
|
@@ -114,9 +117,4 @@ def PhaseField_Folder(folder: str, material: str,
|
|
|
114
117
|
else:
|
|
115
118
|
workFolder = Join(folder, name)
|
|
116
119
|
|
|
117
|
-
path_PythonEf = Get_Path(Get_Path())
|
|
118
|
-
|
|
119
|
-
from . import Display
|
|
120
|
-
Display.MyPrint(workFolder.replace(path_PythonEf,""), 'green')
|
|
121
|
-
|
|
122
120
|
return Join(path, workFolder)
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
# This file is part of the EasyFEA project.
|
|
3
3
|
# EasyFEA is distributed under the terms of the GNU General Public License v3 or later, see LICENSE.txt and CREDITS.md for more information.
|
|
4
4
|
|
|
5
|
-
"""Module providing an interface with PyVista (https://docs.pyvista.org/version/stable/)
|
|
5
|
+
"""Module providing an interface with PyVista (https://docs.pyvista.org/version/stable/).\n
|
|
6
|
+
https://docs.pyvista.org/api/plotting/plotting.html"""
|
|
6
7
|
|
|
7
8
|
from typing import Union, Callable
|
|
8
9
|
from cycler import cycler
|
|
@@ -21,7 +22,7 @@ def Plot(obj, result: Union[str,np.ndarray]=None, deformFactor=0.0, coef=1.0, no
|
|
|
21
22
|
color=None, show_edges=False, edge_color='k', line_width=None,
|
|
22
23
|
show_vertices=False, point_size=None, opacity=1.0,
|
|
23
24
|
style='surface', cmap="jet", n_colors=256, clim=None,
|
|
24
|
-
plotter: pv.Plotter=None, show_grid=False, verticalColobar=True, **kwargs):
|
|
25
|
+
plotter: pv.Plotter=None, show_grid=False, colorbarTitle=None, verticalColobar=True, **kwargs):
|
|
25
26
|
"""Plots the object obj that can be either a simu, mesh, MultiBlock, PolyData.\n
|
|
26
27
|
If you want to plot the solution use plotter.show().
|
|
27
28
|
|
|
@@ -64,6 +65,8 @@ def Plot(obj, result: Union[str,np.ndarray]=None, deformFactor=0.0, coef=1.0, no
|
|
|
64
65
|
The pyvista plotter, by default None and create a new Plotter instance
|
|
65
66
|
show_grid : bool, optionnal
|
|
66
67
|
Show the grid, by default False
|
|
68
|
+
colorbarTitle: str, optionnal
|
|
69
|
+
colorbar title, by default None
|
|
67
70
|
verticalColobar : bool, optionnal
|
|
68
71
|
color bar is vertical, by default True
|
|
69
72
|
**kwargs:
|
|
@@ -95,6 +98,8 @@ def Plot(obj, result: Union[str,np.ndarray]=None, deformFactor=0.0, coef=1.0, no
|
|
|
95
98
|
name = None if pvMesh.n_arrays == 0 else name
|
|
96
99
|
if name != None:
|
|
97
100
|
pvMesh[name] *= coef
|
|
101
|
+
|
|
102
|
+
colorbarTitle = name if colorbarTitle is None else colorbarTitle
|
|
98
103
|
|
|
99
104
|
if plotter is None:
|
|
100
105
|
plotter = _Plotter()
|
|
@@ -120,7 +125,7 @@ def Plot(obj, result: Union[str,np.ndarray]=None, deformFactor=0.0, coef=1.0, no
|
|
|
120
125
|
show_vertices=show_vertices, point_size=point_size,
|
|
121
126
|
opacity=opacity,
|
|
122
127
|
style=style, cmap=cmap, n_colors=n_colors, clim=clim,
|
|
123
|
-
scalar_bar_args={'title':
|
|
128
|
+
scalar_bar_args={'title': colorbarTitle, 'vertical': verticalColobar, pos: val},
|
|
124
129
|
**kwargs)
|
|
125
130
|
|
|
126
131
|
_setCameraPosition(plotter, inDim)
|
|
@@ -161,7 +166,7 @@ def Plot_Mesh(obj, deformFactor=0.0, opacity=1.0, color='cyan', edge_color='blac
|
|
|
161
166
|
return plotter
|
|
162
167
|
|
|
163
168
|
def Plot_Nodes(obj, nodes: np.ndarray=None, showId=False, deformFactor=0, color='red',
|
|
164
|
-
folder="", plotter: pv.Plotter=None):
|
|
169
|
+
folder="", label=None, plotter: pv.Plotter=None):
|
|
165
170
|
"""Plots mesh's nodes.
|
|
166
171
|
|
|
167
172
|
Parameters
|
|
@@ -175,7 +180,9 @@ def Plot_Nodes(obj, nodes: np.ndarray=None, showId=False, deformFactor=0, color=
|
|
|
175
180
|
deformFactor : float, optional
|
|
176
181
|
Factor used to display the deformed solution (0 means no deformations), default 0.0
|
|
177
182
|
color : str, optional
|
|
178
|
-
color, default 'red'
|
|
183
|
+
color, default 'red'
|
|
184
|
+
label : str, optional
|
|
185
|
+
label, by default None
|
|
179
186
|
plotter : pv.Plotter, optional
|
|
180
187
|
The pyvista plotter, by default None and create a new Plotter instance
|
|
181
188
|
|
|
@@ -215,11 +222,13 @@ def Plot_Nodes(obj, nodes: np.ndarray=None, showId=False, deformFactor=0, color=
|
|
|
215
222
|
pvData["myLabels"] = myLabels
|
|
216
223
|
plotter.add_point_labels(pvData, "myLabels", point_color=color, render_points_as_spheres=True)
|
|
217
224
|
else:
|
|
218
|
-
plotter.add_mesh(pvData, color=color, render_points_as_spheres=True)
|
|
225
|
+
plotter.add_mesh(pvData, color=color, label=label, render_points_as_spheres=True)
|
|
219
226
|
|
|
220
227
|
return plotter
|
|
221
228
|
|
|
222
|
-
def Plot_Elements(obj, nodes: np.ndarray=None, dimElem: int=None, showId=False,
|
|
229
|
+
def Plot_Elements(obj, nodes: np.ndarray=None, dimElem: int=None, showId=False,
|
|
230
|
+
deformFactor=0, opacity=1.0, color='red', edge_color='black',
|
|
231
|
+
line_width=None, label=None, plotter: pv.Plotter=None):
|
|
223
232
|
"""Plots the mesh elements corresponding to the given nodes.
|
|
224
233
|
|
|
225
234
|
Parameters
|
|
@@ -242,6 +251,8 @@ def Plot_Elements(obj, nodes: np.ndarray=None, dimElem: int=None, showId=False,
|
|
|
242
251
|
color used to display segments, by default 'black'
|
|
243
252
|
line_width : float, optional
|
|
244
253
|
Thickness of lines, by default None
|
|
254
|
+
label : str, optional
|
|
255
|
+
label, by default None
|
|
245
256
|
plotter : pv.Plotter, optional
|
|
246
257
|
The pyvista plotter, by default None and create a new Plotter instance
|
|
247
258
|
|
|
@@ -264,7 +275,8 @@ def Plot_Elements(obj, nodes: np.ndarray=None, dimElem: int=None, showId=False,
|
|
|
264
275
|
return
|
|
265
276
|
|
|
266
277
|
if plotter == None:
|
|
267
|
-
plotter = Plot(obj, deformFactor=deformFactor, style='wireframe', color=edge_color, line_width=line_width)
|
|
278
|
+
# plotter = Plot(obj, deformFactor=deformFactor, style='wireframe', color=edge_color, line_width=line_width)
|
|
279
|
+
plotter = _Plotter()
|
|
268
280
|
|
|
269
281
|
for groupElem in mesh.Get_list_groupElem(dimElem):
|
|
270
282
|
|
|
@@ -281,7 +293,7 @@ def Plot_Elements(obj, nodes: np.ndarray=None, dimElem: int=None, showId=False,
|
|
|
281
293
|
|
|
282
294
|
pvGroup = _pvGrid(newGroupElem)
|
|
283
295
|
|
|
284
|
-
Plot(pvGroup, opacity=opacity, color=color, edge_color=edge_color, plotter=plotter, line_width=line_width)
|
|
296
|
+
Plot(pvGroup, opacity=opacity, color=color, edge_color=edge_color, plotter=plotter, line_width=line_width, label=label)
|
|
285
297
|
|
|
286
298
|
if showId:
|
|
287
299
|
centers = np.mean(coordo[groupElem.connect[elements]], axis=1)
|
|
@@ -622,11 +634,11 @@ def _Plotter(off_screen=False, add_axes=True, shape=(1,1), linkViews=True):
|
|
|
622
634
|
plotter.subplot(0,0)
|
|
623
635
|
return plotter
|
|
624
636
|
|
|
625
|
-
def _setCameraPosition(plotter: pv.Plotter, inDim: int):
|
|
637
|
+
def _setCameraPosition(plotter: pv.Plotter, inDim: int, elevation=25, azimuth=10):
|
|
626
638
|
plotter.camera_position = 'xy'
|
|
627
639
|
if inDim == 3:
|
|
628
|
-
plotter.camera.elevation
|
|
629
|
-
plotter.camera.azimuth
|
|
640
|
+
plotter.camera.elevation = elevation
|
|
641
|
+
plotter.camera.azimuth = azimuth
|
|
630
642
|
plotter.camera.reset_clipping_range()
|
|
631
643
|
# if inDim == 3:
|
|
632
644
|
# plotter.camera.elevation += 15
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "EasyFEA"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.4"
|
|
8
8
|
description = "User-friendly Python library that simplifies finite element analysis."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Matthieu Noel", email = "matthieu.noel7@gmail.com"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|