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.
Files changed (55) hide show
  1. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Simulations.py +1 -1
  2. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_gmsh_interface.py +8 -4
  3. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_elastic.py +70 -2
  4. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_phasefield.py +31 -22
  5. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_dic.py +2 -2
  6. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_phasefield.py +10 -10
  7. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_utils.py +40 -3
  8. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Display.py +3 -3
  9. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Folder.py +4 -6
  10. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/PyVista_Interface.py +24 -12
  11. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/PKG-INFO +1 -1
  12. {easyfea-1.2.2 → easyfea-1.2.4}/PKG-INFO +1 -1
  13. {easyfea-1.2.2 → easyfea-1.2.4}/pyproject.toml +1 -1
  14. {easyfea-1.2.2 → easyfea-1.2.4}/AUTHORS.md +0 -0
  15. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Geoms.py +0 -0
  16. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/Materials.py +0 -0
  17. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/__about__.py +0 -0
  18. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/__init__.py +0 -0
  19. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/__init__.py +0 -0
  20. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_boundary_conditions.py +0 -0
  21. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_gauss.py +0 -0
  22. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_group_elems.py +0 -0
  23. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_mesh.py +0 -0
  24. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/_utils.py +0 -0
  25. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/__init__.py +0 -0
  26. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_hexa.py +0 -0
  27. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_point.py +0 -0
  28. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_prism.py +0 -0
  29. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_quad.py +0 -0
  30. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_seg.py +0 -0
  31. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_tetra.py +0 -0
  32. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/fem/elems/_tri.py +0 -0
  33. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/__init__.py +0 -0
  34. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_beam.py +0 -0
  35. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_thermal.py +0 -0
  36. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/materials/_utils.py +0 -0
  37. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/Solvers.py +0 -0
  38. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/__init__.py +0 -0
  39. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_beam.py +0 -0
  40. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_elastic.py +0 -0
  41. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_simu.py +0 -0
  42. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/simulations/_thermal.py +0 -0
  43. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Numba_Interface.py +0 -0
  44. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/Paraview_Interface.py +0 -0
  45. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/__init__.py +0 -0
  46. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/_observers.py +0 -0
  47. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA/utilities/_tic.py +0 -0
  48. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/SOURCES.txt +0 -0
  49. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/dependency_links.txt +0 -0
  50. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/requires.txt +0 -0
  51. {easyfea-1.2.2 → easyfea-1.2.4}/EasyFEA.egg-info/top_level.txt +0 -0
  52. {easyfea-1.2.2 → easyfea-1.2.4}/LICENSE.txt +0 -0
  53. {easyfea-1.2.2 → easyfea-1.2.4}/README.md +0 -0
  54. {easyfea-1.2.2 → easyfea-1.2.4}/setup.cfg +0 -0
  55. {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
- testSym = np.linalg.norm(C.T - C)/np.linalg.norm(C)
751
- assert testSym <= 1e-12, "The matrix is not symmetrical."
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
- assert not material.isHeterogeneous, "He decomposition has not been implemented for heterogeneous materials"
743
- # for heterogeneous materials how to make sqrtm ?
744
- # TODO obtain the eigenvalues and eigenvectors of the 2D case with the 3D spectral decomposition?
745
- sqrtC = sqrtm(C)
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
- testC = sqrtC @ sqrtC - C
750
- assert np.linalg.norm(testC)/np.linalg.norm(C) < 1e-12
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
- Epsilont_e_pg = np.einsum('ij,epj->epi', sqrtC, Epsilon_e_pg, optimize='optimal')
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
- cP_e_pg = sqrtC @ (projPt_e_pg @ sqrtC)
772
- cM_e_pg = sqrtC @ (projMt_e_pg @ sqrtC)
773
- # cP_e_pg = C @ projP_e_pg
774
- # cM_e_pg = C @ projM_e_pg
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
- # test_cP = sqrtC @ (projPt_e_pg @ sqrtC) - C @ projP_e_pg
777
- # test_cP = sqrtC @ (projMt_e_pg @ sqrtC) - C @ projM_e_pg
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[bool]:
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[bool]:
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, Kglob, converged
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
- - Kglob: displacement stiffness matrix\n
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
- Kglob = self.__Ku.copy()
314
+ Ku = self.__Ku.copy()
315
315
 
316
- return u_np1, d_np1, Kglob, converged
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
- # Assemblage
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, resultat: str) -> int:
672
+ def __indexResult(self, result: str) -> int:
673
673
 
674
674
  dim = self.dim
675
675
 
676
- if len(resultat) <= 2:
677
- if "x" in resultat:
676
+ if len(result) <= 2:
677
+ if "x" in result:
678
678
  return 0
679
- elif "y" in resultat:
679
+ elif "y" in result:
680
680
  return 1
681
- elif "z" in resultat:
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
- """Save the values of load and displacements in the folder"""
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 forces and displacements.
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 (Ne, Ne).
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=np.linspace(min, max, 11), ncolors=256)
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
- name = f"{name} nL={nL}"
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': name, 'vertical': verticalColobar, pos: val},
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, deformFactor=0, opacity=1.0, color='red', edge_color='black', line_width=None, plotter: pv.Plotter=None):
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 += 25
629
- plotter.camera.azimuth += 10
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: EasyFEA
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: User-friendly Python library that simplifies finite element analysis.
5
5
  Author-email: Matthieu Noel <matthieu.noel7@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: EasyFEA
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: User-friendly Python library that simplifies finite element analysis.
5
5
  Author-email: Matthieu Noel <matthieu.noel7@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "EasyFEA"
7
- version = "1.2.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