emerge 0.5.5__py3-none-any.whl → 0.5.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of emerge might be problematic. Click here for more details.
- emerge/__init__.py +3 -0
- emerge/_emerge/cs.py +2 -2
- emerge/_emerge/elements/ned2_interp.py +21 -26
- emerge/_emerge/elements/nedleg2.py +25 -43
- emerge/_emerge/geo/shapes.py +26 -3
- emerge/_emerge/geometry.py +27 -1
- emerge/_emerge/material.py +1 -0
- emerge/_emerge/mesh3d.py +63 -14
- emerge/_emerge/mesher.py +7 -4
- emerge/_emerge/mth/optimized.py +30 -0
- emerge/_emerge/periodic.py +46 -16
- emerge/_emerge/physics/microwave/assembly/assembler.py +4 -21
- emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +23 -19
- emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +465 -0
- emerge/_emerge/physics/microwave/assembly/robinbc.py +59 -18
- emerge/_emerge/physics/microwave/microwave_3d.py +22 -4
- emerge/_emerge/physics/microwave/microwave_bc.py +101 -35
- emerge/_emerge/physics/microwave/microwave_data.py +1 -1
- emerge/_emerge/plot/pyvista/display.py +40 -7
- emerge/_emerge/plot/pyvista/display_settings.py +1 -0
- emerge/_emerge/simmodel.py +15 -1
- emerge/_emerge/solve_interfaces/cudss_interface.py +44 -2
- emerge/_emerge/solve_interfaces/pardiso_interface.py +1 -0
- emerge/_emerge/solver.py +26 -19
- emerge/ext.py +4 -0
- emerge/lib.py +1 -1
- {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/METADATA +5 -3
- {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/RECORD +31 -30
- emerge/_emerge/elements/legrange2.py +0 -172
- {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/WHEEL +0 -0
- {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/entry_points.txt +0 -0
- {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/licenses/LICENSE +0 -0
emerge/__init__.py
CHANGED
|
@@ -18,6 +18,7 @@ along with this program; if not, see
|
|
|
18
18
|
"""
|
|
19
19
|
import os
|
|
20
20
|
|
|
21
|
+
__version__ = "0.5.6"
|
|
21
22
|
|
|
22
23
|
############################################################
|
|
23
24
|
# HANDLE ENVIRONMENT VARIABLES #
|
|
@@ -57,5 +58,7 @@ from ._emerge.periodic import RectCell, HexCell
|
|
|
57
58
|
from ._emerge.mesher import Algorithm2D, Algorithm3D
|
|
58
59
|
from . import lib
|
|
59
60
|
from ._emerge.howto import _HowtoClass
|
|
61
|
+
|
|
60
62
|
howto = _HowtoClass()
|
|
63
|
+
|
|
61
64
|
logger.debug('Importing complete!')
|
emerge/_emerge/cs.py
CHANGED
|
@@ -128,7 +128,7 @@ def _parse_vector(vec: np.ndarray | tuple[float, float, float] | list[float] | A
|
|
|
128
128
|
return np.array(vec)
|
|
129
129
|
elif isinstance(vec, Axis):
|
|
130
130
|
return vec.vector
|
|
131
|
-
return
|
|
131
|
+
return np.array(vec)
|
|
132
132
|
|
|
133
133
|
def _parse_axis(vec: np.ndarray | tuple[float, float, float] | list[float] | Axis) -> Axis:
|
|
134
134
|
"""Takes an array, tuple, list or Axis and always returns an Axis.
|
|
@@ -145,7 +145,7 @@ def _parse_axis(vec: np.ndarray | tuple[float, float, float] | list[float] | Axi
|
|
|
145
145
|
return Axis(np.array(vec))
|
|
146
146
|
elif isinstance(vec, Axis):
|
|
147
147
|
return vec
|
|
148
|
-
return
|
|
148
|
+
return Axis(np.array(vec))
|
|
149
149
|
|
|
150
150
|
@dataclass
|
|
151
151
|
class Plane:
|
|
@@ -525,7 +525,7 @@ def ned2_tri_interp_full(coords: np.ndarray,
|
|
|
525
525
|
if inside.sum() == 0:
|
|
526
526
|
continue
|
|
527
527
|
|
|
528
|
-
######### INSIDE THE
|
|
528
|
+
######### INSIDE THE TRIANGLE #########
|
|
529
529
|
|
|
530
530
|
x = xs[inside==1]
|
|
531
531
|
y = ys[inside==1]
|
|
@@ -533,26 +533,23 @@ def ned2_tri_interp_full(coords: np.ndarray,
|
|
|
533
533
|
xvs = nodes[0, tris[:,itri]]
|
|
534
534
|
yvs = nodes[1, tris[:,itri]]
|
|
535
535
|
|
|
536
|
-
Ds = compute_distances(xvs, yvs, 0*xvs)
|
|
537
|
-
|
|
538
|
-
L1 = Ds[0,1]
|
|
539
|
-
L2 = Ds[1,2]
|
|
540
|
-
L3 = Ds[0,2]
|
|
541
|
-
|
|
542
|
-
mult = np.array([L1,L2,L3,L3,L1,L2,L3,L1,1,1,1,1,1,1])
|
|
543
|
-
|
|
544
536
|
a_s, b_s, c_s, A = tri_coefficients(xvs, yvs)
|
|
545
537
|
|
|
546
|
-
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri
|
|
538
|
+
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri
|
|
547
539
|
|
|
548
540
|
a1, a2, a3 = a_s
|
|
549
541
|
b1, b2, b3 = b_s
|
|
550
542
|
c1, c2, c3 = c_s
|
|
551
543
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
544
|
+
# original Nedelec-1 order 2 formulation
|
|
545
|
+
# ex = (e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
|
|
546
|
+
# ey = (e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
|
|
547
|
+
# ez = (a1 + b1*x + c1*y)*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y))/(2*A**2)
|
|
555
548
|
|
|
549
|
+
# New Nedelec-1 order 2 formulation
|
|
550
|
+
ex = (-2*A*(e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y)) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y)) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))) - e4*((b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + (b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a1 + b1*x + c1*y)) - e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 - a2 + b1*x - b2*x + c1*y - c2*y) - e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 - a3 + b2*x - b3*x + c2*y - c3*y) - e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 - a3 + b1*x - b3*x + c1*y - c3*y) + e8*((b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + (b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y)))/(8*A**3)
|
|
551
|
+
ey = (-2*A*(e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y)) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y)) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))) - e4*((c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + (c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a1 + b1*x + c1*y)) - e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 - a2 + b1*x - b2*x + c1*y - c2*y) - e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 - a3 + b2*x - b3*x + c2*y - c3*y) - e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 - a3 + b1*x - b3*x + c1*y - c3*y) + e8*((c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + (c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y)))/(8*A**3)
|
|
552
|
+
ez = (-e10*(a2 + b2*x + c2*y)*(A - a2 - b2*x - c2*y)/2 - e11*(a3 + b3*x + c3*y)*(A - a3 - b3*x - c3*y)/2 + e12*(a1 + b1*x + c1*y)*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y)*(a3 + b3*x + c3*y) + e14*(a1 + b1*x + c1*y)*(a3 + b3*x + c3*y) - e9*(a1 + b1*x + c1*y)*(A - a1 - b1*x - c1*y)/2)/A**2
|
|
556
553
|
Ex[inside] = ex
|
|
557
554
|
Ey[inside] = ey
|
|
558
555
|
Ez[inside] = ez
|
|
@@ -621,23 +618,21 @@ def ned2_tri_interp_curl(coords: np.ndarray,
|
|
|
621
618
|
|
|
622
619
|
a_s, b_s, c_s, A = tri_coefficients(xvs, yvs)
|
|
623
620
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
L1 = Ds[0,1]
|
|
627
|
-
L2 = Ds[1,2]
|
|
628
|
-
L3 = Ds[0,2]
|
|
629
|
-
|
|
630
|
-
mult = np.array([L1,L2,L3,L3,L1,L2,L3,L1,1,1,1,1,1,1])
|
|
631
|
-
|
|
632
|
-
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri*mult
|
|
621
|
+
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri
|
|
633
622
|
|
|
634
623
|
a1, a2, a3 = a_s
|
|
635
624
|
b1, b2, b3 = b_s
|
|
636
625
|
c1, c2, c3 = c_s
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
626
|
+
|
|
627
|
+
# original Nedelec-1 order 2 formulation
|
|
628
|
+
#hx = (4*A*(c1*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y)) + (a1 + b1*x + c1*y)*(c1*e10 + c1*e11 + c1*e9 + c2*e12 + c2*e13 + c2*e14)) + jB*(e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y)))/(8*A**3)
|
|
629
|
+
# hy = (4*A*(b1*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y)) + (a1 + b1*x + c1*y)*(b1*e10 + b1*e11 + b1*e9 + b2*e12 + b2*e13 + b2*e14)) - jB*(e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y)))/(8*A**3)
|
|
630
|
+
# hz = (-3*a1*b1*c2*e1 - 3*a1*b1*c3*e3 + 3*a1*b2*c1*e1 + a1*b2*c3*e4 + a1*b2*c3*e8 + 3*a1*b3*c1*e3 - a1*b3*c2*e4 - a1*b3*c2*e8 - 3*a2*b1*c2*e5 + 2*a2*b1*c3*e4 - a2*b1*c3*e8 + 3*a2*b2*c1*e5 - 3*a2*b2*c3*e2 - 2*a2*b3*c1*e4 + a2*b3*c1*e8 + 3*a2*b3*c2*e2 + a3*b1*c2*e4 - 2*a3*b1*c2*e8 - 3*a3*b1*c3*e7 - a3*b2*c1*e4 + 2*a3*b2*c1*e8 - 3*a3*b2*c3*e6 + 3*a3*b3*c1*e7 + 3*a3*b3*c2*e6 - 3*b1**2*c2*e1*x - 3*b1**2*c3*e3*x + 3*b1*b2*c1*e1*x - 3*b1*b2*c2*e5*x + 3*b1*b2*c3*e4*x + 3*b1*b3*c1*e3*x - 3*b1*b3*c2*e8*x - 3*b1*b3*c3*e7*x - 3*b1*c1*c2*e1*y - 3*b1*c1*c3*e3*y - 3*b1*c2**2*e5*y + 3*b1*c2*c3*e4*y - 3*b1*c2*c3*e8*y - 3*b1*c3**2*e7*y + 3*b2**2*c1*e5*x - 3*b2**2*c3*e2*x - 3*b2*b3*c1*e4*x + 3*b2*b3*c1*e8*x + 3*b2*b3*c2*e2*x - 3*b2*b3*c3*e6*x + 3*b2*c1**2*e1*y + 3*b2*c1*c2*e5*y + 3*b2*c1*c3*e8*y - 3*b2*c2*c3*e2*y - 3*b2*c3**2*e6*y + 3*b3**2*c1*e7*x + 3*b3**2*c2*e6*x + 3*b3*c1**2*e3*y - 3*b3*c1*c2*e4*y + 3*b3*c1*c3*e7*y + 3*b3*c2**2*e2*y + 3*b3*c2*c3*e6*y)/(8*A**3)
|
|
631
|
+
|
|
632
|
+
# New Nedelec-1 order 2 formulation
|
|
633
|
+
hx = (4*A*(2*c1*e12*(a2 + b2*x + c2*y) + 2*c1*e14*(a3 + b3*x + c3*y) + c1*e9*(a1 + b1*x + c1*y) - c1*e9*(A - a1 - b1*x - c1*y) + c2*e10*(a2 + b2*x + c2*y) - c2*e10*(A - a2 - b2*x - c2*y) + 2*c2*e12*(a1 + b1*x + c1*y) + 2*c2*e13*(a3 + b3*x + c3*y) + c3*e11*(a3 + b3*x + c3*y) - c3*e11*(A - a3 - b3*x - c3*y) + 2*c3*e13*(a2 + b2*x + c2*y) + 2*c3*e14*(a1 + b1*x + c1*y)) + jB*(2*A*(e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y)) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y)) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))) + e4*((c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + (c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a1 + b1*x + c1*y)) + e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 - a2 + b1*x - b2*x + c1*y - c2*y) + e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 - a3 + b2*x - b3*x + c2*y - c3*y) + e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 - a3 + b1*x - b3*x + c1*y - c3*y) - e8*((c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + (c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y))))/(8*A**3)
|
|
634
|
+
hy = (4*A*(-2*b1*e12*(a2 + b2*x + c2*y) - 2*b1*e14*(a3 + b3*x + c3*y) - b1*e9*(a1 + b1*x + c1*y) + b1*e9*(A - a1 - b1*x - c1*y) - b2*e10*(a2 + b2*x + c2*y) + b2*e10*(A - a2 - b2*x - c2*y) - 2*b2*e12*(a1 + b1*x + c1*y) - 2*b2*e13*(a3 + b3*x + c3*y) - b3*e11*(a3 + b3*x + c3*y) + b3*e11*(A - a3 - b3*x - c3*y) - 2*b3*e13*(a2 + b2*x + c2*y) - 2*b3*e14*(a1 + b1*x + c1*y)) - jB*(2*A*(e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y)) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y)) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))) + e4*((b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + (b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a1 + b1*x + c1*y)) + e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 - a2 + b1*x - b2*x + c1*y - c2*y) + e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 - a3 + b2*x - b3*x + c2*y - c3*y) + e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 - a3 + b1*x - b3*x + c1*y - c3*y) - e8*((b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + (b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y))))/(8*A**3)
|
|
635
|
+
hz = (4*A*(e1*(b1*c2 - b2*c1) + e2*(b2*c3 - b3*c2) + e3*(b1*c3 - b3*c1)) - e4*(b1*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y)) + b2*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y)) - (b1*c3 - b3*c1)*(a2 + b2*x + c2*y) - (b2*c3 - b3*c2)*(a1 + b1*x + c1*y)) + e4*(c1*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y)) + c2*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y)) + (b1*c3 - b3*c1)*(a2 + b2*x + c2*y) + (b2*c3 - b3*c2)*(a1 + b1*x + c1*y)) - e5*(b1 - b2)*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y)) + e5*(c1 - c2)*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y)) + 2*e5*(b1*c2 - b2*c1)*(a1 - a2 + b1*x - b2*x + c1*y - c2*y) - e6*(b2 - b3)*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y)) + e6*(c2 - c3)*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y)) + 2*e6*(b2*c3 - b3*c2)*(a2 - a3 + b2*x - b3*x + c2*y - c3*y) - e7*(b1 - b3)*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y)) + e7*(c1 - c3)*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y)) + 2*e7*(b1*c3 - b3*c1)*(a1 - a3 + b1*x - b3*x + c1*y - c3*y) + e8*(b2*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y)) + b3*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y)) - (b1*c2 - b2*c1)*(a3 + b3*x + c3*y) - (b1*c3 - b3*c1)*(a2 + b2*x + c2*y)) - e8*(c2*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y)) + c3*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y)) + (b1*c2 - b2*c1)*(a3 + b3*x + c3*y) + (b1*c3 - b3*c1)*(a2 + b2*x + c2*y)))/(8*A**3)
|
|
641
636
|
|
|
642
637
|
Ex[inside] = hx*dc[0,0]
|
|
643
638
|
Ey[inside] = hy*dc[1,1]
|
|
@@ -103,6 +103,8 @@ class NedelecLegrange2(FEMBasis):
|
|
|
103
103
|
|
|
104
104
|
self.cs: CoordinateSystem = cs
|
|
105
105
|
|
|
106
|
+
LGORDER = 2
|
|
107
|
+
|
|
106
108
|
##
|
|
107
109
|
nodes = self.mesh.nodes
|
|
108
110
|
self.local_nodes: np.ndarray = np.array(self.cs.in_local_cs(nodes[0,:], nodes[1,:], nodes[2,:]))
|
|
@@ -113,15 +115,23 @@ class NedelecLegrange2(FEMBasis):
|
|
|
113
115
|
self.n_tris: int = self.mesh.n_tris
|
|
114
116
|
self.n_tri_dofs: int = None
|
|
115
117
|
|
|
116
|
-
|
|
118
|
+
if LGORDER == 2:
|
|
119
|
+
self.n_field: int = 2*self.n_edges + 2*self.n_tris + self.n_nodes + self.n_edges
|
|
120
|
+
else:
|
|
121
|
+
self.n_field: int = 2*self.n_edges + 2*self.n_tris + self.n_nodes + self.n_edges*2 + self.n_tris
|
|
122
|
+
|
|
117
123
|
self.n_xy: int = 2*self.n_edges + 2*self.n_tris
|
|
118
|
-
|
|
119
124
|
######## MESH Derived
|
|
120
125
|
Nn = self.mesh.n_nodes
|
|
121
126
|
Ne = self.mesh.n_edges
|
|
122
127
|
Nt = self.mesh.n_tris
|
|
123
128
|
|
|
124
|
-
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if LGORDER==3:
|
|
132
|
+
self.tri_to_field: np.ndarray = np.zeros((8 + 10, self.n_tris), dtype=int)
|
|
133
|
+
else:
|
|
134
|
+
self.tri_to_field: np.ndarray = np.zeros((8 + 6, self.n_tris), dtype=int)
|
|
125
135
|
|
|
126
136
|
self.tri_to_field[:3,:] = self.mesh.tri_to_edge
|
|
127
137
|
self.tri_to_field[3,:] = np.arange(Nt) + Ne
|
|
@@ -129,13 +139,21 @@ class NedelecLegrange2(FEMBasis):
|
|
|
129
139
|
self.tri_to_field[7,:] = np.arange(Nt) + 2*Ne + Nt
|
|
130
140
|
self.tri_to_field[8:11,:] = self.mesh.tris + (2*Ne + 2*Nt) # + E + T + E + T
|
|
131
141
|
self.tri_to_field[11:14,:] = self.mesh.tri_to_edge + (2*Ne + 2*Nt + Nn)
|
|
132
|
-
|
|
142
|
+
|
|
143
|
+
if LGORDER==3:
|
|
144
|
+
# Legrange 3
|
|
145
|
+
self.tri_to_field[14:17,:] = self.mesh.tri_to_edge + (2*Ne + 2*Nt + Nn + Ne)
|
|
146
|
+
self.tri_to_field[17,:] = np.arange(Nt) + (2*Ne + 2*Nt + Nn + Ne + Ne)
|
|
147
|
+
|
|
133
148
|
self.edge_to_field: np.ndarray = np.zeros((5,Ne), dtype=int) #edge mode 1, edge mode 2, edge legrande mode, edge vertex mode 1, edge vertex mode 2
|
|
134
149
|
|
|
135
150
|
self.edge_to_field[0,:] = np.arange(Ne)
|
|
136
151
|
self.edge_to_field[1,:] = np.arange(Ne) + Nt + Ne
|
|
137
|
-
self.edge_to_field[2,:] =
|
|
138
|
-
self.edge_to_field[
|
|
152
|
+
self.edge_to_field[2:4,:] = self.mesh.edges + Ne*2 + Nt*2
|
|
153
|
+
self.edge_to_field[4,:] = np.arange(Ne) + Ne*2 + Nt*2 + Nn
|
|
154
|
+
|
|
155
|
+
if LGORDER==3:
|
|
156
|
+
self.edge_to_field[5:,:] = np.arange(Ne) + Ne*2 + Nt*2 + Nn + Ne
|
|
139
157
|
|
|
140
158
|
##
|
|
141
159
|
self._field: np.ndarray = None
|
|
@@ -148,12 +166,6 @@ class NedelecLegrange2(FEMBasis):
|
|
|
148
166
|
|
|
149
167
|
def interpolate_Ef(self, field: np.ndarray) -> FieldFunctionClass:
|
|
150
168
|
'''Generates the Interpolation function as a function object for a given coordiante basis and origin.'''
|
|
151
|
-
|
|
152
|
-
# def func(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> np.ndarray:
|
|
153
|
-
# xl, yl, zl = self.cs.in_local_cs(xs, ys, zs)
|
|
154
|
-
# Exl, Eyl, Ezl = self.tri_interpolate(field, xl, yl)
|
|
155
|
-
# Ex, Ey, Ez = self.cs.in_global_basis(Exl, Eyl, Ezl)
|
|
156
|
-
# return np.array([Ex, Ey, Ez])
|
|
157
169
|
return FieldFunctionClass(field, self.cs, self.local_nodes, self.mesh.tris, self.tri_to_field, 'E')
|
|
158
170
|
|
|
159
171
|
def interpolate_Hf(self, field: np.ndarray, k0: float, ur: np.ndarray, beta: float) -> FieldFunctionClass:
|
|
@@ -164,11 +176,6 @@ class NedelecLegrange2(FEMBasis):
|
|
|
164
176
|
for i in range(ur.shape[2]):
|
|
165
177
|
urinv[:,:,i] = matinv(ur[:,:,i])
|
|
166
178
|
|
|
167
|
-
# def func(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> np.ndarray:
|
|
168
|
-
# xl, yl, _ = self.cs.in_local_cs(xs, ys, zs)
|
|
169
|
-
# Exl, Eyl, Ezl = self.tri_interpolate_curl(field, xl, yl, urinv, beta)
|
|
170
|
-
# Ex, Ey, Ez = self.cs.in_global_basis(Exl, Eyl, Ezl)
|
|
171
|
-
# return np.array([Ex, Ey, Ez])*constant
|
|
172
179
|
return FieldFunctionClass(field, self.cs, self.local_nodes, self.mesh.tris, self.tri_to_field, 'H', urinv, beta, constant)
|
|
173
180
|
|
|
174
181
|
def tri_interpolate(self, field, xs: np.ndarray, ys: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
@@ -189,29 +196,4 @@ class NedelecLegrange2(FEMBasis):
|
|
|
189
196
|
self.local_nodes,
|
|
190
197
|
self.tri_to_field,
|
|
191
198
|
diadic,
|
|
192
|
-
beta)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
# def interpolate_curl(self, field: np.ndarray, xs: np.ndarray, ys: np.ndarray, zs:np.ndarray, c: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
196
|
-
# """
|
|
197
|
-
# Interpolates the curl of the field at the given points.
|
|
198
|
-
# """
|
|
199
|
-
# return ned2_tet_interp_curl(np.array([xs, ys,zs]), field, self.mesh.tets, self.mesh.tris, self.mesh.edges, self.mesh.nodes, self.tet_to_field, c)
|
|
200
|
-
|
|
201
|
-
# def fieldf(self, field: np.ndarray, basis: np.ndarray = None, origin: np.ndarray = None) -> Callable:
|
|
202
|
-
# if basis is None:
|
|
203
|
-
# basis = np.eye(3)
|
|
204
|
-
|
|
205
|
-
# if origin is None:
|
|
206
|
-
# origin = np.zeros(3)
|
|
207
|
-
|
|
208
|
-
# ibasis = np.linalg.pinv(basis)
|
|
209
|
-
# def func(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> np.ndarray:
|
|
210
|
-
# xyz = np.array([xs, ys, zs]) + origin[:, np.newaxis]
|
|
211
|
-
# xyzg = basis @ xyz
|
|
212
|
-
# return ibasis @ np.array(self.interpolate(field, xyzg[0,:], xyzg[1,:], xyzg[2,:]))
|
|
213
|
-
# return func
|
|
214
|
-
|
|
215
|
-
###### INDEX MAPPINGS
|
|
216
|
-
|
|
217
|
-
|
|
199
|
+
beta)
|
emerge/_emerge/geo/shapes.py
CHANGED
|
@@ -210,6 +210,10 @@ class Cyllinder(GeoVolume):
|
|
|
210
210
|
super().__init__(cyl)
|
|
211
211
|
self._add_face_pointer('front', cs.origin, -cs.zax.np)
|
|
212
212
|
self._add_face_pointer('back', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
213
|
+
self._add_face_pointer('bottom', cs.origin, -cs.zax.np)
|
|
214
|
+
self._add_face_pointer('top', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
215
|
+
self._add_face_pointer('left', cs.origin, -cs.zax.np)
|
|
216
|
+
self._add_face_pointer('right', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
213
217
|
|
|
214
218
|
self.cs: CoordinateSystem = cs
|
|
215
219
|
self.radius = radius
|
|
@@ -273,6 +277,10 @@ class CoaxCyllinder(GeoVolume):
|
|
|
273
277
|
|
|
274
278
|
self._add_face_pointer('front', cs.origin, -cs.zax.np)
|
|
275
279
|
self._add_face_pointer('back', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
280
|
+
self._add_face_pointer('bottom', cs.origin, -cs.zax.np)
|
|
281
|
+
self._add_face_pointer('top', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
282
|
+
self._add_face_pointer('left', cs.origin, -cs.zax.np)
|
|
283
|
+
self._add_face_pointer('right', cs.origin+height*cs.zax.np, cs.zax.np)
|
|
276
284
|
|
|
277
285
|
self.cs = cs
|
|
278
286
|
|
|
@@ -297,13 +305,28 @@ class HalfSphere(GeoVolume):
|
|
|
297
305
|
radius: float,
|
|
298
306
|
position: tuple = (0,0,0),
|
|
299
307
|
direction: tuple = (1,0,0)):
|
|
300
|
-
|
|
308
|
+
|
|
301
309
|
sphere = Sphere(radius, position=position)
|
|
302
310
|
cx, cy, cz = position
|
|
303
311
|
|
|
304
|
-
|
|
312
|
+
dx, dy, dz = direction
|
|
313
|
+
fx = 0.5**dx
|
|
314
|
+
fy = 0.5**dy
|
|
315
|
+
fz = 0.5**dz
|
|
316
|
+
box = Box(2.2*radius*fx, 2.2*radius*fy, 2.2*radius*fz, position=(cx-radius*1.1*dx*0.5,cy-radius*1.1*dy*0.5, cz-radius*1.1*dz*0.5), alignment=Alignment.CENTER)
|
|
317
|
+
|
|
318
|
+
dimtags, _ = gmsh.model.occ.cut(sphere.dimtags, box.dimtags)
|
|
319
|
+
|
|
320
|
+
sphere._exists = False
|
|
321
|
+
box._exists = False
|
|
305
322
|
|
|
306
|
-
|
|
323
|
+
super().__init__([dt[1] for dt in dimtags])
|
|
324
|
+
|
|
325
|
+
self._add_face_pointer('front',np.array(position), np.array(direction))
|
|
326
|
+
self._add_face_pointer('back',np.array(position), np.array(direction))
|
|
327
|
+
self._add_face_pointer('bottom',np.array(position), np.array(direction))
|
|
328
|
+
self._add_face_pointer('face',np.array(position), np.array(direction))
|
|
329
|
+
|
|
307
330
|
|
|
308
331
|
|
|
309
332
|
|
emerge/_emerge/geometry.py
CHANGED
|
@@ -67,7 +67,13 @@ class _GeometryManager:
|
|
|
67
67
|
|
|
68
68
|
def reset(self, modelname: str) -> None:
|
|
69
69
|
self.geometry_list[modelname] = []
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
def lowest_priority(self) -> int:
|
|
72
|
+
return min([geo._priority for geo in self.all_geometries()])
|
|
73
|
+
|
|
74
|
+
def highest_priority(self) -> int:
|
|
75
|
+
return min([geo._priority for geo in self.all_geometries()])
|
|
76
|
+
|
|
71
77
|
class _FacePointer:
|
|
72
78
|
"""The FacePointer class defines a face to be selectable as a
|
|
73
79
|
face normal vector plus an origin. All faces of an object
|
|
@@ -387,6 +393,24 @@ class GeoObject:
|
|
|
387
393
|
self._priority -= 1
|
|
388
394
|
return self
|
|
389
395
|
|
|
396
|
+
def background(self) -> GeoObject:
|
|
397
|
+
"""Set the priority to be on the background.
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
GeoObject: _description_
|
|
401
|
+
"""
|
|
402
|
+
self._priority = _GEOMANAGER.lowest_priority()-10
|
|
403
|
+
return self
|
|
404
|
+
|
|
405
|
+
def foreground(self) -> GeoObject:
|
|
406
|
+
"""Set the priority to be on top.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
GeoObject: _description_
|
|
410
|
+
"""
|
|
411
|
+
self._priority = _GEOMANAGER.highest_priority()+10
|
|
412
|
+
return self
|
|
413
|
+
|
|
390
414
|
def outside(self, *exclude: FaceNames, tags: list[int] | None = None) -> FaceSelection:
|
|
391
415
|
"""Returns the complete set of outside faces.
|
|
392
416
|
|
|
@@ -398,6 +422,8 @@ class GeoObject:
|
|
|
398
422
|
"""
|
|
399
423
|
if tags is None:
|
|
400
424
|
tags = []
|
|
425
|
+
for name in exclude:
|
|
426
|
+
tags.extend(self.face(name).tags)
|
|
401
427
|
dimtags = gmsh.model.get_boundary(self.dimtags, True, False)
|
|
402
428
|
return FaceSelection([t for d,t in dimtags if t not in tags])
|
|
403
429
|
|
emerge/_emerge/material.py
CHANGED
emerge/_emerge/mesh3d.py
CHANGED
|
@@ -146,6 +146,7 @@ class Mesh3D(Mesh):
|
|
|
146
146
|
self.ftag_to_node: dict[int, list[int]] = dict()
|
|
147
147
|
self.ftag_to_edge: dict[int, list[int]] = dict()
|
|
148
148
|
self.vtag_to_tet: dict[int, list[int]] = dict()
|
|
149
|
+
self.etag_to_edge: dict[int, list[int]] = dict()
|
|
149
150
|
|
|
150
151
|
self.exterior_face_tags: list[int] = []
|
|
151
152
|
|
|
@@ -176,7 +177,7 @@ class Mesh3D(Mesh):
|
|
|
176
177
|
search = (min(int(i1),int(i2)), max(int(i1),int(i2)))
|
|
177
178
|
result = self.inv_edges.get(search, -10)
|
|
178
179
|
if result == -10:
|
|
179
|
-
ValueError(f'There is no edge with indices {i1}, {i2}')
|
|
180
|
+
raise ValueError(f'There is no edge with indices {i1}, {i2}')
|
|
180
181
|
return result
|
|
181
182
|
|
|
182
183
|
def get_edge_sign(self, i1: int, i2: int) -> int:
|
|
@@ -240,6 +241,31 @@ class Mesh3D(Mesh):
|
|
|
240
241
|
|
|
241
242
|
return np.array(indices)
|
|
242
243
|
|
|
244
|
+
def domain_edges(self, dimtags: list[tuple[int,int]]) -> np.ndarray:
|
|
245
|
+
"""Returns a np.ndarray of all edge indices corresponding to a set of dimension tags.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
dimtags (list[tuple[int,int]]): A list of dimtags.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
np.ndarray: The list of mesh edge element indices.
|
|
252
|
+
"""
|
|
253
|
+
dimtags_edge = []
|
|
254
|
+
for (d,t) in dimtags:
|
|
255
|
+
if d==1:
|
|
256
|
+
dimtags_edge.append(t)
|
|
257
|
+
if d==2:
|
|
258
|
+
dimtags_edge.extend(gmsh.model.getBoundary([(d,t),], False, False))
|
|
259
|
+
if d==3:
|
|
260
|
+
dts = gmsh.model.getBoundary([(d,t),], False, False)
|
|
261
|
+
dimtags_edge.extend(gmsh.model.getBoundary(dts, False, False))
|
|
262
|
+
|
|
263
|
+
edge_ids = []
|
|
264
|
+
for tag in dimtags_edge:
|
|
265
|
+
edge_ids.extend(self.etag_to_edge[tag[1]])
|
|
266
|
+
edge_ids = np.array(edge_ids)
|
|
267
|
+
return edge_ids
|
|
268
|
+
|
|
243
269
|
def get_face_tets(self, *taglist: list[int]) -> np.ndarray:
|
|
244
270
|
''' Return a list of a tetrahedrons that share a node with any of the nodes in the provided face.'''
|
|
245
271
|
nodes: set = set()
|
|
@@ -271,6 +297,8 @@ class Mesh3D(Mesh):
|
|
|
271
297
|
|
|
272
298
|
|
|
273
299
|
def update(self, periodic_bcs: list[Periodic] | None = None):
|
|
300
|
+
|
|
301
|
+
logger.trace('Generating mesh data.')
|
|
274
302
|
if periodic_bcs is None:
|
|
275
303
|
periodic_bcs = []
|
|
276
304
|
|
|
@@ -282,7 +310,7 @@ class Mesh3D(Mesh):
|
|
|
282
310
|
self.nodes = coords
|
|
283
311
|
self.n_i2t = {i: int(t) for i, t in enumerate(nodes)}
|
|
284
312
|
self.n_t2i = {t: i for i, t in self.n_i2t.items()}
|
|
285
|
-
|
|
313
|
+
logger.trace(f'Total of {self.nodes.shape[1]} nodes imported.')
|
|
286
314
|
## Tetrahedras
|
|
287
315
|
|
|
288
316
|
_, tet_tags, tet_node_tags = gmsh.model.mesh.get_elements(3)
|
|
@@ -297,8 +325,8 @@ class Mesh3D(Mesh):
|
|
|
297
325
|
self.tets = np.array(tet_node_tags).reshape(-1,4).T
|
|
298
326
|
self.tet_i2t = {i: int(t) for i, t in enumerate(tet_tags)}
|
|
299
327
|
self.tet_t2i = {t: i for i, t in self.tet_i2t.items()}
|
|
300
|
-
|
|
301
328
|
self.centers = (self.nodes[:,self.tets[0,:]] + self.nodes[:,self.tets[1,:]] + self.nodes[:,self.tets[2,:]] + self.nodes[:,self.tets[3,:]]) / 4
|
|
329
|
+
logger.trace(f'Total of {self.tets.shape[1]} tetrahedra imported.')
|
|
302
330
|
|
|
303
331
|
# Resort node indices to be sorted on all periodic conditions
|
|
304
332
|
# This sorting makes sure that each edge and triangle on a source face is
|
|
@@ -307,6 +335,7 @@ class Mesh3D(Mesh):
|
|
|
307
335
|
# Then this ensures that if i1>i2>i3 then j1>j2>j3
|
|
308
336
|
|
|
309
337
|
for bc in periodic_bcs:
|
|
338
|
+
logger.trace(f'reassigning ordered node numbers for periodic boundary {bc}')
|
|
310
339
|
nodemap, ids1, ids2 = self._derive_node_map(bc)
|
|
311
340
|
nodemap = {int(a): int(b) for a,b in nodemap.items()}
|
|
312
341
|
self.nodes[:,ids2] = self.nodes[:,ids1]
|
|
@@ -330,25 +359,26 @@ class Mesh3D(Mesh):
|
|
|
330
359
|
triset.add((i1,i2,i4))
|
|
331
360
|
triset.add((i1,i3,i4))
|
|
332
361
|
triset.add((i2,i3,i4))
|
|
333
|
-
|
|
362
|
+
logger.trace(f'Total of {len(edgeset)} unique edges and {len(triset)} unique triangles.')
|
|
363
|
+
|
|
334
364
|
# Edges are effectively Randomly sorted
|
|
335
365
|
# It contains index pairs of vertices edge 1 = (ev1, ev2) etc.
|
|
336
|
-
# Same for
|
|
366
|
+
# Same for triangles
|
|
337
367
|
self.edges = np.array(sorted(list(edgeset))).T
|
|
338
368
|
self.tris = np.array(sorted(list(triset))).T
|
|
339
|
-
|
|
340
369
|
self.tri_centers = (self.nodes[:,self.tris[0,:]] + self.nodes[:,self.tris[1,:]] + self.nodes[:,self.tris[2,:]]) / 3
|
|
370
|
+
|
|
341
371
|
def _hash(ints):
|
|
342
372
|
return tuple(sorted([int(x) for x in ints]))
|
|
343
373
|
|
|
344
374
|
# Map edge index tuples to edge indices
|
|
345
375
|
# This mapping tells which characteristic index pair (4,3) maps to which edge
|
|
376
|
+
logger.trace('Constructing tet/tri/edge and node mappings.')
|
|
346
377
|
self.inv_edges = {(int(self.edges[0,i]), int(self.edges[1,i])): i for i in range(self.edges.shape[1])}
|
|
347
378
|
self.inv_tris = {_hash((self.tris[0,i], self.tris[1,i], self.tris[2,i])): i for i in range(self.tris.shape[1])}
|
|
348
379
|
self.inv_tets = {_hash((self.tets[0,i], self.tets[1,i], self.tets[2,i], self.tets[3,i])): i for i in range(self.tets.shape[1])}
|
|
349
380
|
|
|
350
381
|
# Tet links
|
|
351
|
-
|
|
352
382
|
self.tet_to_edge = np.zeros((6, self.tets.shape[1]), dtype=int)-99999
|
|
353
383
|
self.tet_to_edge_sign = np.zeros((6, self.tets.shape[1]), dtype=int)-999999
|
|
354
384
|
self.tet_to_tri = np.zeros((4, self.tets.shape[1]), dtype=int)-99999
|
|
@@ -414,14 +444,32 @@ class Mesh3D(Mesh):
|
|
|
414
444
|
self.node_to_edge = {key: sorted(list(set(val))) for key, val in self.node_to_edge.items()}
|
|
415
445
|
|
|
416
446
|
## Quantities
|
|
417
|
-
|
|
447
|
+
logger.trace('Computing derived quantaties (centres, areas and lengths).')
|
|
418
448
|
self.edge_centers = (self.nodes[:,self.edges[0,:]] + self.nodes[:,self.edges[1,:]]) / 2
|
|
419
449
|
self.edge_lengths = np.sqrt(np.sum((self.nodes[:,self.edges[0,:]] - self.nodes[:,self.edges[1,:]])**2, axis=0))
|
|
420
450
|
self.areas = np.array([area(self.nodes[:,self.tris[0,i]], self.nodes[:,self.tris[1,i]], self.nodes[:,self.tris[2,i]]) for i in range(self.tris.shape[1])])
|
|
421
451
|
|
|
452
|
+
## Edge tag pairings
|
|
453
|
+
_, edge_tags, edge_node_tags = gmsh.model.mesh.get_elements(1)
|
|
454
|
+
edge_tags = np.array(edge_tags).flatten()
|
|
455
|
+
ent = np.array(edge_node_tags).reshape(-1,2).T
|
|
456
|
+
nET = ent.shape[1]
|
|
457
|
+
self.edge_t2i = {int(edge_tags[i]): self.get_edge(self.n_t2i[ent[0,i]], self.n_t2i[ent[1,i]]) for i in range(nET)}
|
|
458
|
+
self.edge_i2t = {i: t for t, i in self.edge_t2i.items()}
|
|
459
|
+
|
|
460
|
+
edge_dimtags = gmsh.model.get_entities(1)
|
|
461
|
+
for _d, t in edge_dimtags:
|
|
462
|
+
_, edge_tags, node_tags = gmsh.model.mesh.get_elements(1, t)
|
|
463
|
+
if not edge_tags:
|
|
464
|
+
self.etag_to_edge[t] = []
|
|
465
|
+
continue
|
|
466
|
+
self.etag_to_edge[t] = [int(self.edge_t2i[tag]) for tag in edge_tags[0]]
|
|
467
|
+
|
|
468
|
+
|
|
422
469
|
## Tag bindings
|
|
470
|
+
logger.trace('Constructing geometry to mesh mappings.')
|
|
423
471
|
face_dimtags = gmsh.model.get_entities(2)
|
|
424
|
-
for
|
|
472
|
+
for _d,t in face_dimtags:
|
|
425
473
|
domain_tag, f_tags, node_tags = gmsh.model.mesh.get_elements(2, t)
|
|
426
474
|
node_tags = [self.n_t2i[int(t)] for t in node_tags[0]]
|
|
427
475
|
self.ftag_to_node[t] = node_tags
|
|
@@ -430,13 +478,14 @@ class Mesh3D(Mesh):
|
|
|
430
478
|
self.ftag_to_edge[t] = sorted(list(np.unique(self.tri_to_edge[:,self.ftag_to_tri[t]].flatten())))
|
|
431
479
|
|
|
432
480
|
vol_dimtags = gmsh.model.get_entities(3)
|
|
433
|
-
for
|
|
481
|
+
for _d,t in vol_dimtags:
|
|
434
482
|
domain_tag, v_tags, node_tags = gmsh.model.mesh.get_elements(3, t)
|
|
435
483
|
node_tags = [self.n_t2i[int(t)] for t in node_tags[0]]
|
|
436
484
|
node_tags = np.squeeze(np.array(node_tags)).reshape(-1,4).T
|
|
437
485
|
self.vtag_to_tet[t] = [self.get_tet(node_tags[0,i], node_tags[1,i], node_tags[2,i], node_tags[3,i]) for i in range(node_tags.shape[1])]
|
|
438
486
|
|
|
439
487
|
self.defined = True
|
|
488
|
+
logger.trace('Done analyzing mesh.')
|
|
440
489
|
|
|
441
490
|
|
|
442
491
|
## Higher order functions
|
|
@@ -455,7 +504,7 @@ class Mesh3D(Mesh):
|
|
|
455
504
|
Returns:
|
|
456
505
|
tuple[dict[int, int], np.ndarray, np.ndarray]: The node index mapping and the node index arrays
|
|
457
506
|
"""
|
|
458
|
-
|
|
507
|
+
|
|
459
508
|
node_ids_1 = []
|
|
460
509
|
node_ids_2 = []
|
|
461
510
|
|
|
@@ -597,9 +646,9 @@ class Mesh3D(Mesh):
|
|
|
597
646
|
tri_ids = self.get_triangles(face_tags)
|
|
598
647
|
if origin is None:
|
|
599
648
|
nodes = self.nodes[:,self.get_nodes(face_tags)]
|
|
600
|
-
x0 = np.mean(nodes[0,:])
|
|
601
|
-
y0 = np.mean(nodes[1,:])
|
|
602
|
-
z0 = np.mean(nodes[2,:])
|
|
649
|
+
x0 = float(np.mean(nodes[0,:]))
|
|
650
|
+
y0 = float(np.mean(nodes[1,:]))
|
|
651
|
+
z0 = float(np.mean(nodes[2,:]))
|
|
603
652
|
origin = (x0, y0, z0)
|
|
604
653
|
|
|
605
654
|
return SurfaceMesh(self, tri_ids, origin)
|
emerge/_emerge/mesher.py
CHANGED
|
@@ -79,6 +79,7 @@ class Mesher:
|
|
|
79
79
|
self.max_size: float = None
|
|
80
80
|
self.periodic_cell: PeriodicCell = None
|
|
81
81
|
|
|
82
|
+
|
|
82
83
|
@property
|
|
83
84
|
def edge_tags(self) -> list[int]:
|
|
84
85
|
return [tag[1] for tag in gmsh.model.getEntities(1)]
|
|
@@ -244,7 +245,7 @@ class Mesher:
|
|
|
244
245
|
for dimtag in dimtags:
|
|
245
246
|
gmsh.model.mesh.setSizeFromBoundary(dimtag[0], dimtag[1], 0)
|
|
246
247
|
|
|
247
|
-
def set_boundary_size(self, boundary:
|
|
248
|
+
def set_boundary_size(self, boundary: GeoObject | Selection | Iterable,
|
|
248
249
|
size:float,
|
|
249
250
|
growth_rate: float = 1.4,
|
|
250
251
|
max_size: float | None = None) -> None:
|
|
@@ -272,8 +273,10 @@ class Mesher:
|
|
|
272
273
|
nodes = gmsh.model.getBoundary(dimtags, combined=False, oriented=False, recursive=False)
|
|
273
274
|
|
|
274
275
|
disttag = gmsh.model.mesh.field.add("Distance")
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
if boundary.dim==2:
|
|
277
|
+
gmsh.model.mesh.field.setNumbers(disttag, "CurvesList", [n[1] for n in nodes])
|
|
278
|
+
if boundary.dim==3:
|
|
279
|
+
gmsh.model.mesh.field.setNumbers(disttag,'SurfacesList', [n[1] for n in nodes])
|
|
277
280
|
gmsh.model.mesh.field.setNumber(disttag, "Sampling", 100)
|
|
278
281
|
|
|
279
282
|
thtag = gmsh.model.mesh.field.add("Threshold")
|
|
@@ -285,7 +288,7 @@ class Mesher:
|
|
|
285
288
|
|
|
286
289
|
self.mesh_fields.append(thtag)
|
|
287
290
|
|
|
288
|
-
def set_domain_size(self, obj:
|
|
291
|
+
def set_domain_size(self, obj: GeoObject | Selection, size: float):
|
|
289
292
|
"""Manually set the maximum element size inside a domain
|
|
290
293
|
|
|
291
294
|
Args:
|
emerge/_emerge/mth/optimized.py
CHANGED
|
@@ -432,6 +432,36 @@ def matinv(M: np.ndarray) -> np.ndarray:
|
|
|
432
432
|
out = out*det
|
|
433
433
|
return out
|
|
434
434
|
|
|
435
|
+
@njit(f8[:,:](f8[:,:]), cache=True, nogil=True)
|
|
436
|
+
def matinv_r(M: np.ndarray) -> np.ndarray:
|
|
437
|
+
"""Optimized matrix inverse of 3x3 matrix
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
M (np.ndarray): Input matrix M of shape (3,3)
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
np.ndarray: The matrix inverse inv(M)
|
|
444
|
+
"""
|
|
445
|
+
out = np.zeros((3,3), dtype=np.float64)
|
|
446
|
+
|
|
447
|
+
if M[0,1]==0 and M[0,2]==0 and M[1,0]==0 and M[1,2]==0 and M[2,0]==0 and M[2,1]==0:
|
|
448
|
+
out[0,0] = 1/M[0,0]
|
|
449
|
+
out[1,1] = 1/M[1,1]
|
|
450
|
+
out[2,2] = 1/M[2,2]
|
|
451
|
+
else:
|
|
452
|
+
det = M[0,0]*M[1,1]*M[2,2] - M[0,0]*M[1,2]*M[2,1] - M[0,1]*M[1,0]*M[2,2] + M[0,1]*M[1,2]*M[2,0] + M[0,2]*M[1,0]*M[2,1] - M[0,2]*M[1,1]*M[2,0]
|
|
453
|
+
out[0,0] = M[1,1]*M[2,2] - M[1,2]*M[2,1]
|
|
454
|
+
out[0,1] = -M[0,1]*M[2,2] + M[0,2]*M[2,1]
|
|
455
|
+
out[0,2] = M[0,1]*M[1,2] - M[0,2]*M[1,1]
|
|
456
|
+
out[1,0] = -M[1,0]*M[2,2] + M[1,2]*M[2,0]
|
|
457
|
+
out[1,1] = M[0,0]*M[2,2] - M[0,2]*M[2,0]
|
|
458
|
+
out[1,2] = -M[0,0]*M[1,2] + M[0,2]*M[1,0]
|
|
459
|
+
out[2,0] = M[1,0]*M[2,1] - M[1,1]*M[2,0]
|
|
460
|
+
out[2,1] = -M[0,0]*M[2,1] + M[0,1]*M[2,0]
|
|
461
|
+
out[2,2] = M[0,0]*M[1,1] - M[0,1]*M[1,0]
|
|
462
|
+
out = out*det
|
|
463
|
+
return out
|
|
464
|
+
|
|
435
465
|
@njit(cache=True, nogil=True)
|
|
436
466
|
def matmul(M: np.ndarray, vecs: np.ndarray):
|
|
437
467
|
"""Executes a basis transformation of vectors (3,N) with a basis matrix M
|