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.

Files changed (32) hide show
  1. emerge/__init__.py +3 -0
  2. emerge/_emerge/cs.py +2 -2
  3. emerge/_emerge/elements/ned2_interp.py +21 -26
  4. emerge/_emerge/elements/nedleg2.py +25 -43
  5. emerge/_emerge/geo/shapes.py +26 -3
  6. emerge/_emerge/geometry.py +27 -1
  7. emerge/_emerge/material.py +1 -0
  8. emerge/_emerge/mesh3d.py +63 -14
  9. emerge/_emerge/mesher.py +7 -4
  10. emerge/_emerge/mth/optimized.py +30 -0
  11. emerge/_emerge/periodic.py +46 -16
  12. emerge/_emerge/physics/microwave/assembly/assembler.py +4 -21
  13. emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +23 -19
  14. emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +465 -0
  15. emerge/_emerge/physics/microwave/assembly/robinbc.py +59 -18
  16. emerge/_emerge/physics/microwave/microwave_3d.py +22 -4
  17. emerge/_emerge/physics/microwave/microwave_bc.py +101 -35
  18. emerge/_emerge/physics/microwave/microwave_data.py +1 -1
  19. emerge/_emerge/plot/pyvista/display.py +40 -7
  20. emerge/_emerge/plot/pyvista/display_settings.py +1 -0
  21. emerge/_emerge/simmodel.py +15 -1
  22. emerge/_emerge/solve_interfaces/cudss_interface.py +44 -2
  23. emerge/_emerge/solve_interfaces/pardiso_interface.py +1 -0
  24. emerge/_emerge/solver.py +26 -19
  25. emerge/ext.py +4 -0
  26. emerge/lib.py +1 -1
  27. {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/METADATA +5 -3
  28. {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/RECORD +31 -30
  29. emerge/_emerge/elements/legrange2.py +0 -172
  30. {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/WHEEL +0 -0
  31. {emerge-0.5.5.dist-info → emerge-0.5.6.dist-info}/entry_points.txt +0 -0
  32. {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 None
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 None
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 TETRAHEDRON #########
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*mult
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
- 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)
553
- 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)
554
- 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)
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
- Ds = compute_distances(xvs, yvs, 0*xvs)
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
- 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)
639
- 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)
640
- 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)
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
- self.n_field: int = 2*self.n_edges + 2*self.n_tris + self.n_nodes + self.n_edges
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
- self.tri_to_field: np.ndarray = np.zeros((8 + 6, self.n_tris), dtype=int)
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,:] = np.arange(Ne) + Ne*2 + Nt*2 + Nn
138
- self.edge_to_field[3:,:] = self.mesh.edges + Ne*2 + Nt*2
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)
@@ -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
- super().__init__([])
308
+
301
309
  sphere = Sphere(radius, position=position)
302
310
  cx, cy, cz = position
303
311
 
304
- box = Box(1.1*radius, 2.2*radius, 2.2*radius, position=(cx-radius*1.1,cy-radius*1.1, cz-radius*1.1))
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
- self.tag = subtract(sphere, box)[0].tag
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
 
@@ -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
 
@@ -18,6 +18,7 @@
18
18
  import numpy as np
19
19
  from dataclasses import dataclass
20
20
  from typing import Callable
21
+
21
22
  @dataclass
22
23
  class Material:
23
24
  """The Material class generalizes a material in the EMerge FEM environment.
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 traingles
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 d,t in face_dimtags:
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 d,t in vol_dimtags:
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: GeoSurface | FaceSelection | Iterable,
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
- gmsh.model.mesh.field.setNumbers(disttag, "CurvesList", [n[1] for n in nodes])
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: GeoVolume | Selection, size: float):
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:
@@ -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