EasyFEA 1.2.0__tar.gz → 1.2.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.
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/Geoms.py +54 -49
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/Materials.py +2 -2
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_boundary_conditions.py +33 -32
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_gauss.py +4 -5
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_gmsh_interface.py +272 -207
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_group_elems.py +221 -201
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_mesh.py +109 -106
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/_utils.py +8 -8
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/_beam.py +39 -35
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/_elastic.py +89 -81
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/_phasefield.py +309 -233
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/_thermal.py +3 -2
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/_utils.py +63 -55
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/Solvers.py +19 -18
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_beam.py +18 -19
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_dic.py +86 -85
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_elastic.py +38 -41
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_phasefield.py +131 -120
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_simu.py +121 -128
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_thermal.py +10 -11
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/_utils.py +1 -1
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/Display.py +76 -73
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/Folder.py +14 -6
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/Paraview_Interface.py +11 -10
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/PyVista_Interface.py +20 -26
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/_tic.py +6 -5
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA.egg-info/PKG-INFO +5 -2
- {EasyFEA-1.2.0 → easyfea-1.2.2}/PKG-INFO +5 -2
- {EasyFEA-1.2.0 → easyfea-1.2.2}/README.md +4 -1
- {EasyFEA-1.2.0 → easyfea-1.2.2}/pyproject.toml +1 -1
- {EasyFEA-1.2.0 → easyfea-1.2.2}/AUTHORS.md +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/Simulations.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/__about__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_hexa.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_point.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_prism.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_quad.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_seg.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_tetra.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/fem/elems/_tri.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/materials/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/simulations/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/Numba_Interface.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/__init__.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA/utilities/_observers.py +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA.egg-info/SOURCES.txt +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA.egg-info/dependency_links.txt +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA.egg-info/requires.txt +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/EasyFEA.egg-info/top_level.txt +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/LICENSE.txt +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/setup.cfg +0 -0
- {EasyFEA-1.2.0 → easyfea-1.2.2}/setup.py +0 -0
|
@@ -19,7 +19,7 @@ from abc import ABC, abstractmethod
|
|
|
19
19
|
class Point:
|
|
20
20
|
|
|
21
21
|
def __init__(self, x=0.0, y=0.0, z=0.0, isOpen=False, r=0.0):
|
|
22
|
-
"""
|
|
22
|
+
"""Creates a point.
|
|
23
23
|
|
|
24
24
|
Parameters
|
|
25
25
|
----------
|
|
@@ -83,7 +83,7 @@ class Point:
|
|
|
83
83
|
self.__isOpen = value
|
|
84
84
|
|
|
85
85
|
def Check(self, coord) -> bool:
|
|
86
|
-
"""
|
|
86
|
+
"""Checks if coordinates are identical"""
|
|
87
87
|
coord = As_Coordinates(coord)
|
|
88
88
|
n = np.linalg.norm(self.coord)
|
|
89
89
|
n = 1 if n == 0 else n
|
|
@@ -91,11 +91,11 @@ class Point:
|
|
|
91
91
|
return diff <= 1e-12
|
|
92
92
|
|
|
93
93
|
def Translate(self, dx: float=0.0, dy: float=0.0, dz: float=0.0) -> None:
|
|
94
|
-
"""
|
|
94
|
+
"""Translates the point."""
|
|
95
95
|
self.__coord = Translate_coord(self.__coord, dx, dy, dz).ravel()
|
|
96
96
|
|
|
97
97
|
def Rotate(self, theta: float, center: tuple=(0,0,0), direction: tuple=(0,0,1)) -> None:
|
|
98
|
-
"""
|
|
98
|
+
"""Rotates the point with around an axis.
|
|
99
99
|
|
|
100
100
|
Parameters
|
|
101
101
|
----------
|
|
@@ -109,7 +109,7 @@ class Point:
|
|
|
109
109
|
self.__coord = Rotate_coord(self.__coord, theta, center, direction).ravel()
|
|
110
110
|
|
|
111
111
|
def Symmetry(self, point=(0,0,0), n=(1,0,0)) -> None:
|
|
112
|
-
"""
|
|
112
|
+
"""Symmetrizes the point coordinates with a plane.
|
|
113
113
|
|
|
114
114
|
Parameters
|
|
115
115
|
----------
|
|
@@ -166,7 +166,7 @@ class Point:
|
|
|
166
166
|
class _Geom(ABC):
|
|
167
167
|
|
|
168
168
|
def __init__(self, points: list[Point], meshSize: float, name: str, isHollow: bool, isOpen: bool):
|
|
169
|
-
"""
|
|
169
|
+
"""Creates a geometric object.
|
|
170
170
|
|
|
171
171
|
Parameters
|
|
172
172
|
----------
|
|
@@ -193,7 +193,7 @@ class _Geom(ABC):
|
|
|
193
193
|
|
|
194
194
|
@property
|
|
195
195
|
def meshSize(self) -> float:
|
|
196
|
-
"""
|
|
196
|
+
"""element size used for meshing"""
|
|
197
197
|
return self.__meshSize
|
|
198
198
|
|
|
199
199
|
@meshSize.setter
|
|
@@ -235,7 +235,7 @@ class _Geom(ABC):
|
|
|
235
235
|
|
|
236
236
|
@property
|
|
237
237
|
def isHollow(self) -> bool:
|
|
238
|
-
"""Indicates whether the the formed domain is hollow/
|
|
238
|
+
"""Indicates whether the the formed domain is hollow/filled."""
|
|
239
239
|
return self.__isHollow
|
|
240
240
|
|
|
241
241
|
@isHollow.setter
|
|
@@ -254,12 +254,12 @@ class _Geom(ABC):
|
|
|
254
254
|
self.__isOpen = value
|
|
255
255
|
|
|
256
256
|
def Translate(self, dx: float=0.0, dy: float=0.0, dz: float=0.0) -> None:
|
|
257
|
-
"""
|
|
257
|
+
"""Translates the object."""
|
|
258
258
|
# to translate an object, all you have to do is move these points
|
|
259
259
|
[p.Translate(dx,dy,dz) for p in self.__points]
|
|
260
260
|
|
|
261
261
|
def Rotate(self, theta: float, center: tuple=(0,0,0), direction: tuple=(0,0,1)) -> None:
|
|
262
|
-
"""
|
|
262
|
+
"""Rotates the object coordinates around an axis.
|
|
263
263
|
|
|
264
264
|
Parameters
|
|
265
265
|
----------
|
|
@@ -277,7 +277,7 @@ class _Geom(ABC):
|
|
|
277
277
|
[point.Translate(*dec[p]) for p, point in enumerate(self.points)]
|
|
278
278
|
|
|
279
279
|
def Symmetry(self, point=(0,0,0), n=(1,0,0)) -> None:
|
|
280
|
-
"""
|
|
280
|
+
"""Symmetrizes the object coordinates with a plane.
|
|
281
281
|
|
|
282
282
|
Parameters
|
|
283
283
|
----------
|
|
@@ -295,18 +295,20 @@ class _Geom(ABC):
|
|
|
295
295
|
|
|
296
296
|
def Plot(self, ax: plt.Axes=None, color:str="", name:str="", lw=None, ls=None, plotPoints=True) -> plt.Axes:
|
|
297
297
|
|
|
298
|
-
from
|
|
298
|
+
from .utilities import Display
|
|
299
299
|
|
|
300
300
|
if ax is None:
|
|
301
301
|
ax = Display.Init_Axes(3)
|
|
302
302
|
|
|
303
303
|
inDim = 3 if ax.name == '3d' else 2
|
|
304
304
|
|
|
305
|
+
name = self.name if name == "" else name
|
|
306
|
+
|
|
305
307
|
lines, points = self.Get_coord_for_plot()
|
|
306
308
|
if color != "":
|
|
307
|
-
ax.plot(*lines[:,:inDim].T, color=color, label=
|
|
309
|
+
ax.plot(*lines[:,:inDim].T, color=color, label=name, lw=lw, ls=ls)
|
|
308
310
|
else:
|
|
309
|
-
ax.plot(*lines[:,:inDim].T, label=
|
|
311
|
+
ax.plot(*lines[:,:inDim].T, label=name, lw=lw, ls=ls)
|
|
310
312
|
if plotPoints:
|
|
311
313
|
ax.plot(*points[:,:inDim].T, ls='', marker='.',c='black')
|
|
312
314
|
|
|
@@ -341,7 +343,8 @@ class Points(_Geom):
|
|
|
341
343
|
__nbPoints = 0
|
|
342
344
|
|
|
343
345
|
def __init__(self, points: list[Point], meshSize=0.0, isHollow=True, isOpen=False):
|
|
344
|
-
"""
|
|
346
|
+
"""Creates points (list of point).\n
|
|
347
|
+
Can be used to construct a closed surface or a spline.
|
|
345
348
|
|
|
346
349
|
Parameters
|
|
347
350
|
----------
|
|
@@ -367,21 +370,21 @@ class Points(_Geom):
|
|
|
367
370
|
super().__init__(points, meshSize, name, isHollow, isOpen)
|
|
368
371
|
|
|
369
372
|
def Get_Contour(self):
|
|
370
|
-
"""
|
|
371
|
-
|
|
373
|
+
"""Creates a contour from the points.\n
|
|
374
|
+
Creates a fillet if a point has a radius which is not 0."""
|
|
372
375
|
|
|
373
376
|
coordinates = self.coord
|
|
374
377
|
N = coordinates.shape[0]
|
|
375
378
|
mS = self.meshSize
|
|
376
379
|
|
|
377
|
-
# TODO
|
|
380
|
+
# TODO Allows the addition of chamfers?
|
|
378
381
|
|
|
379
382
|
# Get corners
|
|
380
383
|
corners: list[_Geom] = []
|
|
381
384
|
geoms: list[_Geom] = []
|
|
382
385
|
|
|
383
386
|
def Link(idx1: int, idx2: int):
|
|
384
|
-
# this function
|
|
387
|
+
# this function makes the link between corners[idx1] and corners[idx2]
|
|
385
388
|
|
|
386
389
|
# get the last point associated with idx1
|
|
387
390
|
if isinstance(corners[idx1], Point):
|
|
@@ -453,19 +456,19 @@ class Line(_Geom):
|
|
|
453
456
|
|
|
454
457
|
@staticmethod
|
|
455
458
|
def distance(pt1: Point, pt2: Point) -> float:
|
|
456
|
-
"""
|
|
459
|
+
"""Computes the distance between two points."""
|
|
457
460
|
length = np.sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2 + (pt1.z-pt2.z)**2)
|
|
458
461
|
return np.abs(length)
|
|
459
462
|
|
|
460
463
|
@staticmethod
|
|
461
464
|
def get_unitVector(pt1: Point, pt2: Point) -> np.ndarray:
|
|
462
|
-
"""
|
|
465
|
+
"""Creates the unit vector between two points."""
|
|
463
466
|
length = Line.distance(pt1, pt2)
|
|
464
467
|
v = np.array([pt2.x-pt1.x, pt2.y-pt1.y, pt2.z-pt1.z])/length
|
|
465
468
|
return v
|
|
466
469
|
|
|
467
470
|
def __init__(self, pt1: Point, pt2: Point, meshSize=0.0, isOpen=False):
|
|
468
|
-
"""
|
|
471
|
+
"""Creates a line.
|
|
469
472
|
|
|
470
473
|
Parameters
|
|
471
474
|
----------
|
|
@@ -495,7 +498,7 @@ class Line(_Geom):
|
|
|
495
498
|
|
|
496
499
|
@property
|
|
497
500
|
def length(self) -> float:
|
|
498
|
-
"""
|
|
501
|
+
"""distance between the two points of the line"""
|
|
499
502
|
return Line.distance(self.pt1, self.pt2)
|
|
500
503
|
|
|
501
504
|
def Get_coord_for_plot(self) -> tuple[np.ndarray,np.ndarray]:
|
|
@@ -506,7 +509,7 @@ class Domain(_Geom):
|
|
|
506
509
|
__nbDomain = 0
|
|
507
510
|
|
|
508
511
|
def __init__(self, pt1: Point, pt2: Point, meshSize=0.0, isHollow=True):
|
|
509
|
-
"""
|
|
512
|
+
"""Creates a 2d or 3d domain.
|
|
510
513
|
|
|
511
514
|
Parameters
|
|
512
515
|
----------
|
|
@@ -555,7 +558,7 @@ class Circle(_Geom):
|
|
|
555
558
|
__nbCircle = 0
|
|
556
559
|
|
|
557
560
|
def __init__(self, center: Point, diam: float, meshSize=0.0, isHollow=True, isOpen=False, n=(0,0,1)):
|
|
558
|
-
"""
|
|
561
|
+
"""Creates a circle according to its center, diameter and the normal vector.
|
|
559
562
|
|
|
560
563
|
Parameters
|
|
561
564
|
----------
|
|
@@ -589,7 +592,7 @@ class Circle(_Geom):
|
|
|
589
592
|
circleArc2 = CircleArc(self.pt2, self.pt3, center=center, meshSize=meshSize, isOpen=isOpen)
|
|
590
593
|
circleArc3 = CircleArc(self.pt3, self.pt4, center=center, meshSize=meshSize, isOpen=isOpen)
|
|
591
594
|
circleArc4 = CircleArc(self.pt4, self.pt1, center=center, meshSize=meshSize, isOpen=isOpen)
|
|
592
|
-
#
|
|
595
|
+
# creates the contour object associated with the circle
|
|
593
596
|
self.contour = Contour([circleArc1, circleArc2, circleArc3, circleArc4], isHollow, isOpen)
|
|
594
597
|
|
|
595
598
|
Circle.__nbCircle += 1
|
|
@@ -618,7 +621,7 @@ class Circle(_Geom):
|
|
|
618
621
|
|
|
619
622
|
@property
|
|
620
623
|
def diam(self) -> float:
|
|
621
|
-
"""circle diameter"""
|
|
624
|
+
"""circle's diameter"""
|
|
622
625
|
p1 = self.pt1.coord
|
|
623
626
|
pC = self.center.coord
|
|
624
627
|
return np.linalg.norm(p1-pC) * 2
|
|
@@ -664,11 +667,12 @@ class CircleArc(_Geom):
|
|
|
664
667
|
__nbCircleArc = 0
|
|
665
668
|
|
|
666
669
|
def __init__(self, pt1: Point, pt2: Point, center:Point=None, R:float=None, P:Point=None, meshSize=0.0, n=(0,0,1), isOpen=False, coef=1):
|
|
667
|
-
"""
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
670
|
+
"""Creates a circular arc using several methods:\n
|
|
671
|
+
- 1: with 2 points, a radius R and a normal vector.\n
|
|
672
|
+
- 2: with 2 points and a center.\n
|
|
673
|
+
- 3: with 2 points and a point P belonging to the circle.\n
|
|
674
|
+
The methods are chosen in the following order 3 2 1.\n
|
|
675
|
+
This means that if you enter P, the other methods will not be used.
|
|
672
676
|
|
|
673
677
|
Parameters
|
|
674
678
|
----------
|
|
@@ -695,7 +699,7 @@ class CircleArc(_Geom):
|
|
|
695
699
|
assert isinstance(pt1, Point), "must be a point"
|
|
696
700
|
assert isinstance(pt2, Point), "must be a point"
|
|
697
701
|
|
|
698
|
-
#
|
|
702
|
+
# checks that pt1 and pt2 dont share the same coordinates
|
|
699
703
|
assert not pt1.Check(pt2), 'pt1 and pt2 are on the same coordinates'
|
|
700
704
|
|
|
701
705
|
if P != None:
|
|
@@ -723,7 +727,7 @@ class CircleArc(_Geom):
|
|
|
723
727
|
self.pt2 = pt2
|
|
724
728
|
"""Ending point of the arc."""
|
|
725
729
|
|
|
726
|
-
# Here we'll create an intermediate point, because in gmsh, circular arcs are limited to an angle
|
|
730
|
+
# Here we'll create an intermediate point, because in gmsh, circular arcs are limited to an pi angle.
|
|
727
731
|
|
|
728
732
|
i1 = (pt1-center).coord
|
|
729
733
|
i2 = (pt2-center).coord
|
|
@@ -810,7 +814,7 @@ class Contour(_Geom):
|
|
|
810
814
|
__nbContour = 0
|
|
811
815
|
|
|
812
816
|
def __init__(self, geoms: list[Union[Line,CircleArc,Points]], isHollow=True, isOpen=False):
|
|
813
|
-
"""
|
|
817
|
+
"""Creates a contour from a list of line circleArc and points.
|
|
814
818
|
|
|
815
819
|
Parameters
|
|
816
820
|
----------
|
|
@@ -910,7 +914,7 @@ def Normalize_vect(vect: np.ndarray) -> np.ndarray:
|
|
|
910
914
|
|
|
911
915
|
def Rotation_matrix(vect: np.ndarray, theta: float) -> np.ndarray:
|
|
912
916
|
"""Gets the rotation matrix for turning along an axis with theta angle (rad).\n
|
|
913
|
-
p(x,y) =
|
|
917
|
+
p(x,y) = mat • p(i,j)\n
|
|
914
918
|
https://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle"""
|
|
915
919
|
|
|
916
920
|
x, y, z = Normalize_vect(vect)
|
|
@@ -925,7 +929,7 @@ def Rotation_matrix(vect: np.ndarray, theta: float) -> np.ndarray:
|
|
|
925
929
|
return mat
|
|
926
930
|
|
|
927
931
|
def AngleBetween_a_b(a: np.ndarray, b: np.ndarray) -> float:
|
|
928
|
-
"""
|
|
932
|
+
"""Computes the angle between vectors a and b (rad).
|
|
929
933
|
https://math.stackexchange.com/questions/878785/how-to-find-an-angle-in-range0-360-between-2-vectors"""
|
|
930
934
|
|
|
931
935
|
a = As_Coordinates(a)
|
|
@@ -950,7 +954,7 @@ def AngleBetween_a_b(a: np.ndarray, b: np.ndarray) -> float:
|
|
|
950
954
|
return angle
|
|
951
955
|
|
|
952
956
|
def Translate_coord(coord: np.ndarray, dx: float=0.0, dy: float=0.0, dz: float=0.0) -> np.ndarray:
|
|
953
|
-
"""
|
|
957
|
+
"""Translates the coordinates."""
|
|
954
958
|
|
|
955
959
|
oldCoord = np.reshape(coord, (-1, 3))
|
|
956
960
|
|
|
@@ -961,7 +965,7 @@ def Translate_coord(coord: np.ndarray, dx: float=0.0, dy: float=0.0, dz: float=0
|
|
|
961
965
|
return newCoord
|
|
962
966
|
|
|
963
967
|
def Rotate_coord(coord: np.ndarray, theta: float, center: tuple=(0,0,0), direction: tuple=(0,0,1)) -> np.ndarray:
|
|
964
|
-
"""
|
|
968
|
+
"""Rotates the coordinates arround a specified center and axis.
|
|
965
969
|
|
|
966
970
|
Parameters
|
|
967
971
|
----------
|
|
@@ -995,7 +999,7 @@ def Rotate_coord(coord: np.ndarray, theta: float, center: tuple=(0,0,0), directi
|
|
|
995
999
|
return newCoord
|
|
996
1000
|
|
|
997
1001
|
def Symmetry_coord(coord: np.ndarray, point=(0,0,0), n=(1,0,0)) -> np.ndarray:
|
|
998
|
-
"""
|
|
1002
|
+
"""Symmetrizes coordinates with a plane.
|
|
999
1003
|
|
|
1000
1004
|
Parameters
|
|
1001
1005
|
----------
|
|
@@ -1024,8 +1028,9 @@ def Symmetry_coord(coord: np.ndarray, point=(0,0,0), n=(1,0,0)) -> np.ndarray:
|
|
|
1024
1028
|
return newCoord
|
|
1025
1029
|
|
|
1026
1030
|
def Jacobian_Matrix(i: np.ndarray, k: np.ndarray) -> np.ndarray:
|
|
1027
|
-
"""
|
|
1031
|
+
"""Computes the Jacobian matrix to transform local coordinates (i,j,k) to global (x,y,z) coordinates.\n
|
|
1028
1032
|
p(x,y,z) = J • p(i,j,k) and p(i,j,k) = inv(J) • p(x,y,z)\n\n
|
|
1033
|
+
|
|
1029
1034
|
ix jx kx\n
|
|
1030
1035
|
iy jy ky\n
|
|
1031
1036
|
iz jz kz
|
|
@@ -1053,8 +1058,8 @@ def Jacobian_Matrix(i: np.ndarray, k: np.ndarray) -> np.ndarray:
|
|
|
1053
1058
|
return F
|
|
1054
1059
|
|
|
1055
1060
|
def Points_Rayon(P0: np.ndarray, P1: np.ndarray, P2: np.ndarray, r: float) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
1056
|
-
"""
|
|
1057
|
-
|
|
1061
|
+
"""Computes fillet in a corner P0.\n
|
|
1062
|
+
returns A, B, C
|
|
1058
1063
|
|
|
1059
1064
|
Parameters
|
|
1060
1065
|
----------
|
|
@@ -1065,7 +1070,7 @@ def Points_Rayon(P0: np.ndarray, P1: np.ndarray, P2: np.ndarray, r: float) -> tu
|
|
|
1065
1070
|
P2 : np.ndarray
|
|
1066
1071
|
coordinates after P0 coordinates
|
|
1067
1072
|
r : float
|
|
1068
|
-
radius at point P0
|
|
1073
|
+
radius (or fillet) at point P0
|
|
1069
1074
|
|
|
1070
1075
|
Returns
|
|
1071
1076
|
-------
|
|
@@ -1099,8 +1104,8 @@ def Points_Rayon(P0: np.ndarray, P1: np.ndarray, P2: np.ndarray, r: float) -> tu
|
|
|
1099
1104
|
return A, B, C
|
|
1100
1105
|
|
|
1101
1106
|
def Circle_Triangle(p1, p2, p3) -> np.ndarray:
|
|
1102
|
-
"""
|
|
1103
|
-
|
|
1107
|
+
"""Returns triangle's center for the circumcicular arc formed by 3 points.\n
|
|
1108
|
+
returns center
|
|
1104
1109
|
"""
|
|
1105
1110
|
|
|
1106
1111
|
# https://math.stackexchange.com/questions/1076177/3d-coordinates-of-circle-center-given-three-point-on-the-circle
|
|
@@ -1125,7 +1130,7 @@ def Circle_Triangle(p1, p2, p3) -> np.ndarray:
|
|
|
1125
1130
|
return center
|
|
1126
1131
|
|
|
1127
1132
|
def Circle_Coord(coord: np.ndarray, R: float, n: np.ndarray) -> np.ndarray:
|
|
1128
|
-
"""
|
|
1133
|
+
"""Returns center from coordinates a radius and and a vector normal to the circle.\n
|
|
1129
1134
|
return center
|
|
1130
1135
|
"""
|
|
1131
1136
|
|
|
@@ -1156,7 +1161,8 @@ def Circle_Coord(coord: np.ndarray, R: float, n: np.ndarray) -> np.ndarray:
|
|
|
1156
1161
|
return center
|
|
1157
1162
|
|
|
1158
1163
|
def Points_Intersect_Circles(circle1: Circle, circle2: Circle) -> np.ndarray:
|
|
1159
|
-
"""
|
|
1164
|
+
"""Computes the coordinates at the intersection of the two circles (i,3).\n
|
|
1165
|
+
This only works if they're on the same plane.
|
|
1160
1166
|
|
|
1161
1167
|
Parameters
|
|
1162
1168
|
----------
|
|
@@ -1192,7 +1198,6 @@ def Points_Intersect_Circles(circle1: Circle, circle2: Circle) -> np.ndarray:
|
|
|
1192
1198
|
if d == r1 + r2:
|
|
1193
1199
|
return p3.reshape(1, 3)
|
|
1194
1200
|
else:
|
|
1195
|
-
|
|
1196
1201
|
i = Normalize_vect(p2-p1)
|
|
1197
1202
|
k = np.array([0,0,1])
|
|
1198
1203
|
j = np.cross(k, i)
|
|
@@ -2,7 +2,7 @@
|
|
|
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 containing
|
|
5
|
+
"""Module containing constitutive laws for materials, including elastic, damage, thermal, and beam materials."""
|
|
6
6
|
|
|
7
7
|
from .materials import Reshape_variable
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ from .materials._phasefield import PhaseField
|
|
|
22
22
|
# Beam
|
|
23
23
|
# ----------------------------------------------
|
|
24
24
|
|
|
25
|
-
from .materials._beam import _Beam,
|
|
25
|
+
from .materials._beam import _Beam, BeamStructure, Beam_Elas_Isot
|
|
26
26
|
|
|
27
27
|
# ----------------------------------------------
|
|
28
28
|
# Thermal
|
|
@@ -14,15 +14,15 @@ class BoundaryCondition:
|
|
|
14
14
|
Parameters
|
|
15
15
|
----------
|
|
16
16
|
problemType : str
|
|
17
|
-
|
|
17
|
+
Problem type.
|
|
18
18
|
nodes : np.ndarray
|
|
19
19
|
Nodes on which the condition is applied.
|
|
20
20
|
dofs : np.ndarray
|
|
21
|
-
Degrees of freedom associated with nodes and directions.
|
|
21
|
+
Degrees of freedom (associated with nodes and directions).
|
|
22
22
|
directions : np.ndarray
|
|
23
|
-
|
|
23
|
+
Dofs directions (e.g. [“x”, “y”], [“rz”]).
|
|
24
24
|
dofsValues : np.ndarray
|
|
25
|
-
|
|
25
|
+
Dofs values.
|
|
26
26
|
description : str
|
|
27
27
|
Description of the boundary condition.
|
|
28
28
|
"""
|
|
@@ -32,68 +32,69 @@ class BoundaryCondition:
|
|
|
32
32
|
self.__dofs = np.asarray(dofs, dtype=int)
|
|
33
33
|
assert self.dofs.size % self.nodes.size == 0, f"dofs.size must be a multiple of {self.nodes.size}"
|
|
34
34
|
self.__dofsValues = np.asarray(dofsValues, dtype=float)
|
|
35
|
+
# assert dofs.size == dofsValues.size, "must be the same size." don't uncomment !
|
|
36
|
+
# This assertion is commented out to illustrate that using Lagrange conditions might bypass this size check.
|
|
35
37
|
self.description = description
|
|
36
38
|
|
|
37
39
|
@property
|
|
38
40
|
def problemType(self) -> str:
|
|
39
|
-
"""
|
|
41
|
+
"""type of problem"""
|
|
40
42
|
return self.__problemType
|
|
41
43
|
|
|
42
44
|
@property
|
|
43
45
|
def nodes(self) -> np.ndarray:
|
|
44
|
-
"""
|
|
46
|
+
"""nodes on which the condition is applied"""
|
|
45
47
|
return self.__nodes.copy()
|
|
46
48
|
|
|
47
49
|
@property
|
|
48
50
|
def dofs(self) -> np.ndarray:
|
|
49
|
-
"""
|
|
51
|
+
"""degrees of freedom associated with the nodes and directions"""
|
|
50
52
|
return self.__dofs.copy()
|
|
51
53
|
|
|
52
54
|
@property
|
|
53
55
|
def dofsValues(self) -> np.ndarray:
|
|
54
|
-
"""
|
|
56
|
+
"""values applied"""
|
|
55
57
|
return self.__dofsValues.copy()
|
|
56
58
|
|
|
57
59
|
@property
|
|
58
60
|
def directions(self) -> np.ndarray:
|
|
59
|
-
"""
|
|
61
|
+
"""dofs directions"""
|
|
60
62
|
return self.__directions.copy()
|
|
61
63
|
|
|
62
64
|
@staticmethod
|
|
63
65
|
def Get_nBc(problemType: str, list_Bc_Condition: list) -> int:
|
|
64
|
-
"""
|
|
66
|
+
"""Returns the number of conditions for the problem type.
|
|
65
67
|
|
|
66
68
|
Parameters
|
|
67
69
|
----------
|
|
68
70
|
problemType : str
|
|
69
|
-
|
|
71
|
+
Problem type.
|
|
70
72
|
list_Bc_Condition : list[BoundaryCondition]
|
|
71
73
|
List of boundary conditions.
|
|
72
74
|
|
|
73
75
|
Returns
|
|
74
76
|
-------
|
|
75
77
|
int
|
|
76
|
-
nBc
|
|
78
|
+
Number of boundary conditions (nBc).
|
|
77
79
|
"""
|
|
78
80
|
list_Bc_Condition: list[BoundaryCondition] = list_Bc_Condition
|
|
79
81
|
return len([1 for bc in list_Bc_Condition if bc.problemType == problemType])
|
|
80
82
|
|
|
81
|
-
|
|
82
83
|
@staticmethod
|
|
83
84
|
def Get_dofs(problemType: str, list_Bc_Condition: list) -> list[int]:
|
|
84
|
-
"""
|
|
85
|
+
"""Returns the degrees of freedom for the problem type.
|
|
85
86
|
|
|
86
87
|
Parameters
|
|
87
88
|
----------
|
|
88
89
|
problemType : str
|
|
89
|
-
|
|
90
|
+
Problem type.
|
|
90
91
|
list_Bc_Condition : list[BoundaryCondition]
|
|
91
92
|
List of boundary conditions.
|
|
92
93
|
|
|
93
94
|
Returns
|
|
94
95
|
-------
|
|
95
96
|
list
|
|
96
|
-
|
|
97
|
+
List of degrees of freedom.
|
|
97
98
|
"""
|
|
98
99
|
list_Bc_Condition: list[BoundaryCondition] = list_Bc_Condition
|
|
99
100
|
dofs: list[int] = []
|
|
@@ -102,19 +103,19 @@ class BoundaryCondition:
|
|
|
102
103
|
|
|
103
104
|
@staticmethod
|
|
104
105
|
def Get_values(problemType: str, list_Bc_Condition: list) -> list[float]:
|
|
105
|
-
"""
|
|
106
|
+
"""Returns the dofs values for problem type.
|
|
106
107
|
|
|
107
108
|
Parameters
|
|
108
109
|
----------
|
|
109
110
|
problemType : str
|
|
110
|
-
|
|
111
|
+
Problem type.
|
|
111
112
|
list_Bc_Condition : list[BoundaryCondition]
|
|
112
|
-
List of boundary
|
|
113
|
+
List of boundary condition.
|
|
113
114
|
|
|
114
115
|
Returns
|
|
115
116
|
-------
|
|
116
|
-
list
|
|
117
|
-
|
|
117
|
+
list[float]
|
|
118
|
+
dofs values.
|
|
118
119
|
"""
|
|
119
120
|
list_Bc_Condition: list[BoundaryCondition] = list_Bc_Condition
|
|
120
121
|
values: list[float] = []
|
|
@@ -123,21 +124,21 @@ class BoundaryCondition:
|
|
|
123
124
|
|
|
124
125
|
@staticmethod
|
|
125
126
|
def Get_dofs_nodes(availableDirections: list[str], nodes: np.ndarray, directions: list[str]) -> np.ndarray:
|
|
126
|
-
"""
|
|
127
|
+
"""Retrieves degrees of freedom (dofs) associated with the nodes.
|
|
127
128
|
|
|
128
129
|
Parameters
|
|
129
130
|
----------
|
|
130
131
|
availableDirections : list[str]
|
|
131
|
-
|
|
132
|
+
Available directions as a list of strings. Must be a unique string list.
|
|
132
133
|
nodes : np.ndarray
|
|
133
|
-
Nodes.
|
|
134
|
+
Nodes for which dofs are calculated.
|
|
134
135
|
directions : list[str]
|
|
135
|
-
Directions.
|
|
136
|
+
Directions corresponding to the nodes.
|
|
136
137
|
|
|
137
138
|
Returns
|
|
138
139
|
-------
|
|
139
140
|
np.ndarray
|
|
140
|
-
|
|
141
|
+
degrees of freedom.
|
|
141
142
|
"""
|
|
142
143
|
|
|
143
144
|
nodes = np.asarray(nodes, dtype=int).ravel()
|
|
@@ -163,20 +164,20 @@ class BoundaryCondition:
|
|
|
163
164
|
class LagrangeCondition(BoundaryCondition):
|
|
164
165
|
|
|
165
166
|
def __init__(self, problemType: str, nodes: np.ndarray, dofs: np.ndarray, directions: np.ndarray, dofsValues: np.ndarray, lagrangeCoefs: np.ndarray, description=""):
|
|
166
|
-
"""
|
|
167
|
+
"""Creates a Lagrange condition (based on a boundary condition).
|
|
167
168
|
|
|
168
169
|
Parameters
|
|
169
170
|
----------
|
|
170
171
|
problemType : str
|
|
171
|
-
|
|
172
|
+
Problem type.
|
|
172
173
|
nodes : np.ndarray
|
|
173
174
|
Nodes on which the condition is applied.
|
|
174
175
|
dofs : np.ndarray
|
|
175
|
-
Degrees of freedom associated with nodes and directions.
|
|
176
|
+
Degrees of freedom (associated with nodes and directions).
|
|
176
177
|
directions : np.ndarray
|
|
177
|
-
|
|
178
|
+
Dofs directions.
|
|
178
179
|
dofsValues : np.ndarray
|
|
179
|
-
|
|
180
|
+
Dofs values.
|
|
180
181
|
lagrangeCoefs : np.ndarray
|
|
181
182
|
Lagrange coefficients.
|
|
182
183
|
description : str, optional
|
|
@@ -188,4 +189,4 @@ class LagrangeCondition(BoundaryCondition):
|
|
|
188
189
|
@property
|
|
189
190
|
def lagrangeCoefs(self) -> np.ndarray:
|
|
190
191
|
"""Lagrange coefficients."""
|
|
191
|
-
return self.__lagrangeCoefs.copy()
|
|
192
|
+
return self.__lagrangeCoefs.copy()
|
|
@@ -12,14 +12,14 @@ from ._utils import ElemType, MatrixType
|
|
|
12
12
|
class Gauss:
|
|
13
13
|
|
|
14
14
|
def __init__(self, elemType: str, matrixType: str):
|
|
15
|
-
"""
|
|
15
|
+
"""Creates integration points.
|
|
16
16
|
|
|
17
17
|
Parameters
|
|
18
18
|
----------
|
|
19
19
|
elemType : str
|
|
20
|
-
element type
|
|
20
|
+
element type.
|
|
21
21
|
matrixType : str
|
|
22
|
-
[MatrixType.rigi, MatrixType.mass, MatrixType.beam]
|
|
22
|
+
matrix type (e.g [MatrixType.rigi, MatrixType.mass, MatrixType.beam])
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
coord, weights = Gauss._Gauss_factory(elemType, matrixType)
|
|
@@ -212,7 +212,6 @@ class Gauss:
|
|
|
212
212
|
"""available [6, 8]\n
|
|
213
213
|
orderX = [3, 3]\n
|
|
214
214
|
orderYZ = [2, 3]"""
|
|
215
|
-
|
|
216
215
|
|
|
217
216
|
# X, Y, Z -> base code aster
|
|
218
217
|
# z, x, y -> gmsh
|
|
@@ -374,7 +373,7 @@ class Gauss:
|
|
|
374
373
|
x, y, z, weights = Gauss._Prism(nPg)
|
|
375
374
|
|
|
376
375
|
else:
|
|
377
|
-
raise Exception("Element not implemented")
|
|
376
|
+
raise Exception("Element not implemented.")
|
|
378
377
|
|
|
379
378
|
if dim == 1:
|
|
380
379
|
coord = np.asarray([x]).T.reshape((nPg,1))
|