emerge 1.0.6__py3-none-any.whl → 1.0.7__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 CHANGED
@@ -18,7 +18,7 @@ along with this program; if not, see
18
18
  """
19
19
  import os
20
20
 
21
- __version__ = "1.0.6"
21
+ __version__ = "1.0.7"
22
22
 
23
23
  ############################################################
24
24
  # HANDLE ENVIRONMENT VARIABLES #
@@ -61,3 +61,48 @@ def index_interp(coords: np.ndarray,
61
61
  prop[inside] = itet
62
62
 
63
63
  return prop
64
+
65
+ @njit(f8[:](f8[:,:], i8[:,:], f8[:,:], i8[:], f8[:]), cache=True, nogil=True)
66
+ def constant_interp(coords: np.ndarray,
67
+ tets: np.ndarray,
68
+ nodes: np.ndarray,
69
+ tetids: np.ndarray,
70
+ value: np.ndarray):
71
+ ''' Nedelec 2 tetrahedral interpolation of the analytic curl'''
72
+ # Solution has shape (nEdges, nsols)
73
+ nNodes = coords.shape[1]
74
+
75
+ prop = np.full((nNodes, ), 0, dtype=np.float64)
76
+
77
+ for i_iter in range(tetids.shape[0]):
78
+ itet = tetids[i_iter]
79
+
80
+ iv1, iv2, iv3, iv4 = tets[:, itet]
81
+
82
+ v1 = nodes[:,iv1]
83
+ v2 = nodes[:,iv2]
84
+ v3 = nodes[:,iv3]
85
+ v4 = nodes[:,iv4]
86
+
87
+ bv1 = v2 - v1
88
+ bv2 = v3 - v1
89
+ bv3 = v4 - v1
90
+
91
+ blocal = np.zeros((3,3))
92
+ blocal[:,0] = bv1
93
+ blocal[:,1] = bv2
94
+ blocal[:,2] = bv3
95
+ basis = np.linalg.pinv(blocal)
96
+
97
+ coords_offset = coords - v1[:,np.newaxis]
98
+ coords_local = (basis @ (coords_offset))
99
+
100
+
101
+ inside = ((coords_local[0,:] + coords_local[1,:] + coords_local[2,:]) <= 1.00000001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6) & (coords_local[2,:] >= -1e-6)
102
+
103
+ if inside.sum() == 0:
104
+ continue
105
+
106
+ prop[inside] = value[itet]
107
+
108
+ return prop
@@ -59,7 +59,7 @@ class MatProperty:
59
59
  self._z: np.ndarray = np.array([], dtype=np.float64)
60
60
 
61
61
  self._fmax = lambda f: value
62
-
62
+
63
63
  def initialize(self, x: np.ndarray, y: np.ndarray, z: np.ndarray, ids: np.ndarray) -> None:
64
64
  self._apply_to = np.concatenate([self._apply_to, ids])
65
65
  self._x = np.concatenate([self._x, x])
emerge/_emerge/mesh3d.py CHANGED
@@ -196,7 +196,6 @@ class Mesh3D(Mesh):
196
196
  raise ValueError(f'There is no tetrahedron with indices {i1}, {i2}, {i3}, {i4}')
197
197
  return output
198
198
 
199
-
200
199
  def get_tetrahedra(self, vol_tags: Union[int, list[int]]) -> np.ndarray:
201
200
  if isinstance(vol_tags, int):
202
201
  vol_tags = [vol_tags,]
@@ -270,6 +269,37 @@ class Mesh3D(Mesh):
270
269
  nodes.update(self.get_nodes(tags))
271
270
  return np.array([i for i, tet in enumerate(self.tets.T) if not set(tet).isdisjoint(nodes)])
272
271
 
272
+ def _get_dimtags(self, nodes: list[int] | None = None, edges: list[int] | None = None) -> list[tuple[int, int]]:
273
+ """Returns the geometry dimtags associated with a set of nodes and edges"""
274
+ if nodes is None:
275
+ nodes = []
276
+ if edges is None:
277
+ edges = []
278
+ nodes = set(nodes)
279
+ edges = set(edges)
280
+ dimtags = []
281
+
282
+ # Test faces
283
+ for tag, f_nodes in self.ftag_to_node.items():
284
+ if set(f_nodes).isdisjoint(nodes):
285
+ continue
286
+ dimtags.append((2,tag))
287
+
288
+ for tag, f_edges in self.ftag_to_edge.items():
289
+ if set(f_edges).isdisjoint(edges):
290
+ continue
291
+ dimtags.append((2,tag))
292
+
293
+ # test volumes
294
+ for tag, f_tets in self.vtag_to_tet.items():
295
+ v_nodes = set(self.tets[:,f_tets].flatten())
296
+ if not v_nodes.isdisjoint(nodes):
297
+ dimtags.append((3,tag))
298
+ v_edges = set(self.tet_to_edge[:,f_tets].flatten())
299
+ if not v_edges.isdisjoint(edges):
300
+ dimtags.append((3,tag))
301
+ return sorted(dimtags)
302
+
273
303
  def get_nodes(self, face_tags: Union[int, list[int]]) -> np.ndarray:
274
304
  '''Returns a numpyarray of all the nodes that belong to the given face tags'''
275
305
  if isinstance(face_tags, int):
@@ -572,7 +602,7 @@ class Mesh3D(Mesh):
572
602
  materials.append(vol.material)
573
603
  vol.material._hash_key = i
574
604
  i += 1
575
-
605
+
576
606
  xs = self.centers[0,:]
577
607
  ys = self.centers[1,:]
578
608
  zs = self.centers[2,:]
@@ -597,7 +627,7 @@ class Mesh3D(Mesh):
597
627
  def plot_gmsh(self) -> None:
598
628
  gmsh.fltk.run()
599
629
 
600
- def find_edge_groups(self, edge_ids: np.ndarray) -> list[tuple[Any,...]]:
630
+ def find_edge_groups(self, edge_ids: np.ndarray) -> list[tuple[int,...]]:
601
631
  """
602
632
  Find the groups of edges in the mesh.
603
633
 
emerge/_emerge/mesher.py CHANGED
@@ -75,6 +75,7 @@ class Mesher:
75
75
  self.objects: list[GeoObject] = []
76
76
  self.size_definitions: list[tuple[int, float]] = []
77
77
  self.mesh_fields: list[int] = []
78
+ self._amr_fields: list[int] = []
78
79
  self.min_size: float = None
79
80
  self.max_size: float = None
80
81
  self.periodic_cell: PeriodicCell = None
@@ -222,8 +223,13 @@ class Mesher:
222
223
  gmsh.model.mesh.field.set_numbers(ctag, "CurvesList", tags)
223
224
  gmsh.model.mesh.field.set_number(ctag, "VIn", max_size)
224
225
  self.mesh_fields.append(ctag)
226
+
227
+ def _reset_amr_points(self) -> None:
228
+ for tag in self._amr_fields:
229
+ gmsh.model.mesh.field.remove(tag)
230
+ self._amr_fields = []
225
231
 
226
- def _set_size_on_point(self, tags: list[int], max_size: float) -> None:
232
+ def _set_amr_point(self, tags: list[int], max_size: float) -> None:
227
233
  """Define the size of the mesh on a point
228
234
 
229
235
  Args:
@@ -233,7 +239,7 @@ class Mesher:
233
239
  ctag = gmsh.model.mesh.field.add("Constant")
234
240
  gmsh.model.mesh.field.set_numbers(ctag, "PointsList", tags)
235
241
  gmsh.model.mesh.field.set_number(ctag, "VIn", max_size)
236
- self.mesh_fields.append(ctag)
242
+ self._amr_fields.append(ctag)
237
243
 
238
244
  def _configure_mesh_size(self, discretizer: Callable, resolution: float):
239
245
  """Defines the mesh sizes based on a discretization callable.
@@ -267,7 +273,7 @@ class Mesher:
267
273
  logger.debug(f'Setting mesh size:{1000*size:.3f}mm in domains: {tag}')
268
274
  self._set_size_in_domain([tag,], size)
269
275
 
270
- gmsh.model.mesh.field.setNumbers(mintag, "FieldsList", self.mesh_fields)
276
+ gmsh.model.mesh.field.setNumbers(mintag, "FieldsList", self.mesh_fields + self._amr_fields)
271
277
  gmsh.model.mesh.field.setAsBackgroundMesh(mintag)
272
278
 
273
279
  for tag, size in self.size_definitions:
@@ -279,7 +285,19 @@ class Mesher:
279
285
  logger.trace(f'Unsetting mesh size constraint for domains: {dimtags}')
280
286
  for dimtag in dimtags:
281
287
  gmsh.model.mesh.setSizeFromBoundary(dimtag[0], dimtag[1], 0)
282
-
288
+
289
+ def add_refinement_point(self,
290
+ coordinate: np.ndarray,
291
+ refinement: float,
292
+ size: float,
293
+ gr: float = 1.5):
294
+ x0, y0, z0 = coordinate
295
+ disttag = gmsh.model.mesh.field.add("MathEval")
296
+ newsize = refinement*size
297
+ funcstr = f"({newsize})/({gr}) - (1-{gr})/({gr}) * Sqrt((x-({x0}))^2+ (y-({y0}))^2 + (z-({z0}))^2)"
298
+ gmsh.model.mesh.field.setString(disttag, "F", funcstr)
299
+ self.mesh_fields.append(disttag)
300
+
283
301
  def set_boundary_size(self,
284
302
  boundary: GeoObject | Selection | Iterable,
285
303
  size:float,