emerge 0.5.1__py3-none-any.whl → 0.5.2__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 (47) hide show
  1. emerge/_emerge/bc.py +11 -8
  2. emerge/_emerge/cs.py +2 -2
  3. emerge/_emerge/elements/femdata.py +14 -14
  4. emerge/_emerge/elements/index_interp.py +1 -1
  5. emerge/_emerge/elements/ned2_interp.py +1 -1
  6. emerge/_emerge/elements/nedelec2.py +4 -4
  7. emerge/_emerge/elements/nedleg2.py +9 -9
  8. emerge/_emerge/geo/horn.py +1 -1
  9. emerge/_emerge/geo/modeler.py +18 -19
  10. emerge/_emerge/geo/operations.py +13 -10
  11. emerge/_emerge/geo/pcb.py +70 -69
  12. emerge/_emerge/geo/pcb_tools/macro.py +14 -13
  13. emerge/_emerge/geo/pmlbox.py +1 -1
  14. emerge/_emerge/geometry.py +46 -32
  15. emerge/_emerge/logsettings.py +3 -3
  16. emerge/_emerge/material.py +11 -11
  17. emerge/_emerge/mesh3d.py +81 -59
  18. emerge/_emerge/mesher.py +26 -21
  19. emerge/_emerge/mth/pairing.py +2 -2
  20. emerge/_emerge/periodic.py +34 -31
  21. emerge/_emerge/physics/microwave/adaptive_freq.py +14 -11
  22. emerge/_emerge/physics/microwave/assembly/assembler.py +61 -57
  23. emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +43 -8
  24. emerge/_emerge/physics/microwave/assembly/robinbc.py +5 -5
  25. emerge/_emerge/physics/microwave/microwave_3d.py +40 -20
  26. emerge/_emerge/physics/microwave/microwave_bc.py +114 -95
  27. emerge/_emerge/physics/microwave/microwave_data.py +33 -33
  28. emerge/_emerge/physics/microwave/simjob.py +12 -12
  29. emerge/_emerge/physics/microwave/sparam.py +12 -12
  30. emerge/_emerge/physics/microwave/touchstone.py +1 -1
  31. emerge/_emerge/plot/display.py +12 -6
  32. emerge/_emerge/plot/pyvista/display.py +44 -39
  33. emerge/_emerge/plot/pyvista/display_settings.py +1 -1
  34. emerge/_emerge/plot/simple_plots.py +15 -15
  35. emerge/_emerge/selection.py +35 -39
  36. emerge/_emerge/simmodel.py +29 -39
  37. emerge/_emerge/simulation_data.py +19 -14
  38. emerge/_emerge/solve_interfaces/pardiso_interface.py +24 -18
  39. emerge/_emerge/solver.py +52 -52
  40. emerge/lib.py +243 -243
  41. {emerge-0.5.1.dist-info → emerge-0.5.2.dist-info}/METADATA +1 -1
  42. emerge-0.5.2.dist-info/RECORD +81 -0
  43. emerge/_emerge/plot/grapher.py +0 -93
  44. emerge-0.5.1.dist-info/RECORD +0 -82
  45. {emerge-0.5.1.dist-info → emerge-0.5.2.dist-info}/WHEEL +0 -0
  46. {emerge-0.5.1.dist-info → emerge-0.5.2.dist-info}/entry_points.txt +0 -0
  47. {emerge-0.5.1.dist-info → emerge-0.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -17,7 +17,7 @@
17
17
 
18
18
  import numpy as np
19
19
  from dataclasses import dataclass
20
-
20
+ from typing import Callable
21
21
  @dataclass
22
22
  class Material:
23
23
  """The Material class generalizes a material in the EMerge FEM environment.
@@ -34,11 +34,11 @@ class Material:
34
34
  ur: float = 1
35
35
  tand: float = 0
36
36
  cond: float = 0
37
- _neff: float = None
38
- _fer: callable = None
39
- _fur: callable = None
37
+ _neff: float | None = None
38
+ _fer: Callable | None= None
39
+ _fur: Callable | None = None
40
40
  color: str = "#BEBEBE"
41
- _color_rgb: tuple[int,int,int] = None
41
+ _color_rgb: tuple[float,float,float] = (0.5, 0.5, 0.5)
42
42
  opacity: float = 1.0
43
43
 
44
44
  def __post_init__(self):
@@ -73,34 +73,34 @@ class Material:
73
73
  return np.abs(np.sqrt(er*(1-1j*self.tand)*ur))
74
74
 
75
75
  @property
76
- def fer2d(self) -> callable:
76
+ def fer2d(self) -> Callable:
77
77
  if self._fer is None:
78
78
  return lambda x,y: self.er*(1-1j*self.tand)*np.ones_like(x)
79
79
  else:
80
80
  return self._fer
81
81
 
82
82
  @property
83
- def fur2d(self) -> callable:
83
+ def fur2d(self) -> Callable:
84
84
  if self._fur is None:
85
85
 
86
86
  return lambda x,y: self.ur*np.ones_like(x)
87
87
  else:
88
88
  return self._fur
89
89
  @property
90
- def fer3d(self) -> callable:
90
+ def fer3d(self) -> Callable:
91
91
  if self._fer is None:
92
92
  return lambda x,y,z: self.er*(1-1j*self.tand)*np.ones_like(x)
93
93
  else:
94
94
  return self._fer
95
95
 
96
96
  @property
97
- def fur3d(self) -> callable:
97
+ def fur3d(self) -> Callable:
98
98
  if self._fur is None:
99
99
  return lambda x,y,z: self.ur*np.ones_like(x)
100
100
  else:
101
101
  return self._fur
102
102
  @property
103
- def fer3d_mat(self) -> callable:
103
+ def fer3d_mat(self) -> Callable:
104
104
  if self._fer is None:
105
105
 
106
106
  return lambda x,y,z: np.repeat(self.ermat[:, :, np.newaxis], x.shape[0], axis=2)
@@ -108,7 +108,7 @@ class Material:
108
108
  return self._fer
109
109
 
110
110
  @property
111
- def fur3d_mat(self) -> callable:
111
+ def fur3d_mat(self) -> Callable:
112
112
  if self._fur is None:
113
113
  return lambda x,y,z: np.repeat(self.urmat[:, :, np.newaxis], x.shape[0], axis=2)
114
114
  else:
emerge/_emerge/mesh3d.py CHANGED
@@ -16,11 +16,11 @@
16
16
  # <https://www.gnu.org/licenses/>.
17
17
 
18
18
  from __future__ import annotations
19
- import gmsh
19
+ import gmsh # type: ignore
20
20
  import numpy as np
21
- from numba import njit, f8
21
+ from numba import njit, f8 # type: ignore
22
22
  from .mesher import Mesher
23
- from typing import Union, List, Tuple, Callable
23
+ from typing import Union, List, Tuple, Callable, Any
24
24
  from collections import defaultdict
25
25
  from .geometry import GeoVolume
26
26
  from .mth.optimized import outward_normal
@@ -75,8 +75,10 @@ def tri_ordering(i1: int, i2: int, i3: int) -> int:
75
75
  '''
76
76
  return np.sign(np.sign(i2-1) + np.sign(i3-i2) + np.sign(i1-i3))
77
77
 
78
+ class Mesh:
79
+ pass
78
80
 
79
- class Mesh3D:
81
+ class Mesh3D(Mesh):
80
82
  """A Mesh managing all 3D mesh related properties.
81
83
 
82
84
  Relevant mesh data such as mappings between nodes(vertices), edges, triangles and tetrahedra
@@ -89,54 +91,54 @@ class Mesh3D:
89
91
  self.geometry: Mesher = mesher
90
92
 
91
93
  # All spatial objects
92
- self.nodes: np.ndarray = None
93
- self.n_i2t: dict = None
94
- self.n_t2i: dict = None
94
+ self.nodes: np.ndarray = np.array([])
95
+ self.n_i2t: dict = dict()
96
+ self.n_t2i: dict = dict()
95
97
 
96
98
  # tets colletions
97
- self.tets: np.ndarray = None
98
- self.tet_i2t: dict = None
99
- self.tet_t2i: dict = None
100
- self.centers: np.ndarray = None
99
+ self.tets: np.ndarray = np.array([])
100
+ self.tet_i2t: dict = dict()
101
+ self.tet_t2i: dict = dict()
102
+ self.centers: np.ndarray = np.array([])
101
103
 
102
104
  # triangles
103
- self.tris: np.ndarray = None
104
- self.tri_i2t: dict = None
105
- self.tri_t2i: dict = None
106
- self.areas: np.ndarray = None
107
- self.tri_centers: np.ndarray = None
105
+ self.tris: np.ndarray = np.array([])
106
+ self.tri_i2t: dict = dict()
107
+ self.tri_t2i: dict = dict()
108
+ self.areas: np.ndarray = np.array([])
109
+ self.tri_centers: np.ndarray = np.array([])
108
110
 
109
111
  # edges
110
- self.edges: np.ndarray = None
111
- self.edge_i2t: dict = None
112
- self.edge_t2i: dict = None
113
- self.edge_centers: np.ndarray = None
114
- self.edge_lengths: np.ndarray = None
112
+ self.edges: np.ndarray = np.array([])
113
+ self.edge_i2t: dict = dict()
114
+ self.edge_t2i: dict = dict()
115
+ self.edge_centers: np.ndarray = np.array([])
116
+ self.edge_lengths: np.ndarray = np.array([])
115
117
 
116
118
  # Inverse mappings
117
- self.inv_edges: dict = None
118
- self.inv_tris: dict = None
119
- self.inv_tets: dict = None
119
+ self.inv_edges: dict = dict()
120
+ self.inv_tris: dict = dict()
121
+ self.inv_tets: dict = dict()
120
122
 
121
123
  # Mappings
122
124
 
123
- self.tet_to_edge: np.ndarray = None
124
- self.tet_to_edge_sign: np.ndarray = None
125
- self.tet_to_tri: np.ndarray = None
126
- self.tri_to_tet: np.ndarray = None
127
- self.tri_to_edge: np.ndarray = None
128
- self.tri_to_edge_sign: np.ndarray = None
129
- self.edge_to_tri: defaultdict = None
130
- self.node_to_edge: defaultdict = None
125
+ self.tet_to_edge: np.ndarray = np.array([])
126
+ self.tet_to_edge_sign: np.ndarray = np.array([])
127
+ self.tet_to_tri: np.ndarray = np.array([])
128
+ self.tri_to_tet: np.ndarray = np.array([])
129
+ self.tri_to_edge: np.ndarray = np.array([])
130
+ self.tri_to_edge_sign: np.ndarray = np.array([])
131
+ self.edge_to_tri: defaultdict | dict = defaultdict()
132
+ self.node_to_edge: defaultdict | dict = defaultdict()
131
133
 
132
134
  # Physics mappings
133
135
 
134
- self.tet_to_field: np.ndarray = None
135
- self.edge_to_field: np.ndarray = None
136
- self.tri_to_field: np.ndarray = None
136
+ self.tet_to_field: np.ndarray = np.array([])
137
+ self.edge_to_field: np.ndarray = np.array([])
138
+ self.tri_to_field: np.ndarray = np.array([])
137
139
 
138
140
  ## States
139
- self.defined = False
141
+ self.defined: bool = False
140
142
 
141
143
 
142
144
  ## Memory
@@ -144,6 +146,8 @@ class Mesh3D:
144
146
  self.ftag_to_node: dict[int, list[int]] = dict()
145
147
  self.ftag_to_edge: dict[int, list[int]] = dict()
146
148
  self.vtag_to_tet: dict[int, list[int]] = dict()
149
+
150
+ self.exterior_face_tags: list[int] = []
147
151
 
148
152
  @property
149
153
  def n_edges(self) -> int:
@@ -170,7 +174,9 @@ class Mesh3D:
170
174
  if i1==i2:
171
175
  raise ValueError("Edge cannot be formed by the same node.")
172
176
  search = (min(int(i1),int(i2)), max(int(i1),int(i2)))
173
- result = self.inv_edges.get(search, None)
177
+ result = self.inv_edges.get(search, -10)
178
+ if result == -10:
179
+ ValueError(f'There is no edge with indices {i1}, {i2}')
174
180
  return result
175
181
 
176
182
  def get_edge_sign(self, i1: int, i2: int) -> int:
@@ -183,13 +189,19 @@ class Mesh3D:
183
189
 
184
190
  def get_tri(self, i1, i2, i3) -> int:
185
191
  '''Return the triangle index given the three node indices'''
186
- return self.inv_tris.get(tuple(sorted((int(i1), int(i2), int(i3)))), None)
192
+ output = self.inv_tris.get(tuple(sorted((int(i1), int(i2), int(i3)))), None)
193
+ if output is None:
194
+ raise ValueError(f'There is no triangle with indices {i1}, {i2}, {i3}')
195
+ return output
187
196
 
188
197
  def get_tet(self, i1, i2, i3, i4) -> int:
189
198
  '''Return the tetrahedron index given the four node indices'''
190
- return self.inv_tets.get(tuple(sorted((int(i1), int(i2), int(i3), int(i4)))), None)
199
+ output = self.inv_tets.get(tuple(sorted((int(i1), int(i2), int(i3), int(i4)))), None)
200
+ if output is None:
201
+ raise ValueError(f'There is no tetrahedron with indices {i1}, {i2}, {i3}, {i4}')
202
+ return output
191
203
 
192
- def boundary_triangles(self, dimtags: list[tuple[int, int]] = None) -> np.ndarray:
204
+ def boundary_triangles(self, dimtags: list[tuple[int, int]] | None = None) -> np.ndarray:
193
205
  if dimtags is None:
194
206
  outputtags = []
195
207
  for tags in self.ftag_to_tri.values():
@@ -230,7 +242,7 @@ class Mesh3D:
230
242
 
231
243
  def get_face_tets(self, *taglist: list[int]) -> np.ndarray:
232
244
  ''' Return a list of a tetrahedrons that share a node with any of the nodes in the provided face.'''
233
- nodes = set()
245
+ nodes: set = set()
234
246
  for tags in taglist:
235
247
  nodes.update(self.get_nodes(tags))
236
248
  return np.array([i for i, tet in enumerate(self.tets.T) if not set(tet).isdisjoint(nodes)])
@@ -258,7 +270,7 @@ class Mesh3D:
258
270
  return np.array(sorted(list(set(edges))))
259
271
 
260
272
 
261
- def update(self, periodic_bcs: list[Periodic] = None):
273
+ def update(self, periodic_bcs: list[Periodic] | None = None):
262
274
  if periodic_bcs is None:
263
275
  periodic_bcs = []
264
276
 
@@ -406,8 +418,7 @@ class Mesh3D:
406
418
  self.edge_centers = (self.nodes[:,self.edges[0,:]] + self.nodes[:,self.edges[1,:]]) / 2
407
419
  self.edge_lengths = np.sqrt(np.sum((self.nodes[:,self.edges[0,:]] - self.nodes[:,self.edges[1,:]])**2, axis=0))
408
420
  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])])
409
-
410
-
421
+
411
422
  ## Tag bindings
412
423
  face_dimtags = gmsh.model.get_entities(2)
413
424
  for d,t in face_dimtags:
@@ -466,11 +477,11 @@ class Mesh3D:
466
477
  all_node_ids = np.unique(np.array(node_ids_1 + node_ids_2))
467
478
  dsmin = shortest_distance(self.nodes[:,all_node_ids])
468
479
 
469
- node_ids_1 = sorted(list(set(node_ids_1)))
470
- node_ids_2 = sorted(list(set(node_ids_2)))
480
+ node_ids_1_arry = np.sort(np.unique(np.array(node_ids_1)))
481
+ node_ids_2_arry = np.sort(np.unique(np.array(node_ids_2)))
471
482
  dv = np.array(bc.dv)
472
483
 
473
- nodemap = pair_coordinates(self.nodes, node_ids_1, node_ids_2, dv, dsmin/2)
484
+ nodemap = pair_coordinates(self.nodes, node_ids_1_arry, node_ids_2_arry, dv, dsmin/2)
474
485
  node_ids_2_unsorted = [nodemap[i] for i in sorted(node_ids_1)]
475
486
  node_ids_2_sorted = sorted(node_ids_2_unsorted)
476
487
  conv_map = {i1: i2 for i1, i2 in zip(node_ids_2_unsorted, node_ids_2_sorted)}
@@ -499,7 +510,7 @@ class Mesh3D:
499
510
  def plot_gmsh(self) -> None:
500
511
  gmsh.fltk.run()
501
512
 
502
- def find_edge_groups(self, edge_ids: np.ndarray) -> dict:
513
+ def find_edge_groups(self, edge_ids: np.ndarray) -> list[tuple[Any,...]]:
503
514
  """
504
515
  Find the groups of edges in the mesh.
505
516
 
@@ -568,7 +579,7 @@ class Mesh3D:
568
579
 
569
580
  def boundary_surface(self,
570
581
  face_tags: Union[int, list[int]],
571
- origin: tuple[float, float, float] = None) -> SurfaceMesh:
582
+ origin: tuple[float, float, float] | None = None) -> SurfaceMesh:
572
583
  """Returns a SurfaceMesh class that is a 2D mesh isolated from the 3D mesh
573
584
 
574
585
  The mesh will be based on the given set of face tags.
@@ -593,7 +604,7 @@ class Mesh3D:
593
604
 
594
605
  return SurfaceMesh(self, tri_ids, origin)
595
606
 
596
- class SurfaceMesh:
607
+ class SurfaceMesh(Mesh):
597
608
 
598
609
  def __init__(self,
599
610
  original: Mesh3D,
@@ -614,21 +625,22 @@ class SurfaceMesh:
614
625
 
615
626
  self.original_tris: np.ndarray = original.tris
616
627
 
617
- self.old_new_node_map: dict[int,int] = old_to_new_node_id_map
628
+ self.old_new_node_map: dict = old_to_new_node_id_map
618
629
  self.original: Mesh3D = original
619
630
  self._alignment_origin: np.ndarray = np.array(origin).astype(np.float64)
620
631
  self.nodes: np.ndarray = original.nodes[:, unique_nodes]
621
632
  self.tris: np.ndarray = new_tris
622
633
 
623
634
  ## initialize derived
624
- self.edge_centers: np.ndarray = None
625
- self.edge_tris: np.ndarray = None
635
+ self.edge_centers: np.ndarray = np.array([])
636
+ self.edge_tris: np.ndarray = np.array([])
626
637
  self.n_nodes = self.nodes.shape[1]
627
638
  self.n_tris = self.tris.shape[1]
628
- self.n_edges = None
629
- self.areas: np.ndarray = None
630
- self.normals: np.ndarray = None
631
-
639
+ self.n_edges: float = -1
640
+ self.areas: np.ndarray = np.array([])
641
+ self.normals: np.ndarray = np.array([])
642
+ self.tri_to_edge: np.ndarray = np.array([])
643
+ self.edge_to_tri: dict | defaultdict = dict()
632
644
  # Generate derived
633
645
  self.update()
634
646
 
@@ -642,22 +654,26 @@ class SurfaceMesh:
642
654
  self.flipY()
643
655
  if ax.lower()=='z':
644
656
  self.flipZ()
657
+ return self
645
658
  #self.tris[(0,1),:] = self.tris[(1,0),:]
646
659
 
647
660
  def flipX(self) -> SurfaceMesh:
648
661
  self.nodes[0,:] = -self.nodes[0,:]
649
662
  self.normals[0,:] = -self.normals[0,:]
650
663
  self.edge_centers[0,:] = -self.edge_centers[0,:]
651
-
664
+ return self
665
+
652
666
  def flipY(self) -> SurfaceMesh:
653
667
  self.nodes[1,:] = -self.nodes[1,:]
654
668
  self.normals[1,:] = -self.normals[1,:]
655
669
  self.edge_centers[1,:] = -self.edge_centers[1,:]
670
+ return self
656
671
 
657
672
  def flipZ(self) -> SurfaceMesh:
658
673
  self.nodes[2,:] = -self.nodes[2,:]
659
674
  self.normals[2,:] = -self.normals[2,:]
660
675
  self.edge_centers[2,:] = -self.edge_centers[2,:]
676
+ return self
661
677
 
662
678
  def from_source_tri(self, triid: int) -> int | None:
663
679
  ''' Returns a triangle index from the old mesh to the new mesh.'''
@@ -685,6 +701,8 @@ class SurfaceMesh:
685
701
  raise ValueError("Edge cannot be formed by the same node.")
686
702
  search = (min(int(i1),int(i2)), max(int(i1),int(i2)))
687
703
  result = self.inv_edges.get(search, None)
704
+ if result is None:
705
+ raise ValueError(f'There is no edge with indices {i1}, {i2}')
688
706
  return result
689
707
 
690
708
  def get_edge_sign(self, i1: int, i2: int) -> int:
@@ -697,7 +715,11 @@ class SurfaceMesh:
697
715
 
698
716
  def get_tri(self, i1, i2, i3) -> int:
699
717
  '''Return the triangle index given the three node indices'''
700
- return self.inv_tris.get(tuple(sorted((int(i1), int(i2), int(i3)))), None)
718
+ result = self.inv_tris.get(tuple(sorted((int(i1), int(i2), int(i3)))), None)
719
+ if result is None:
720
+ raise ValueError(f'There is no triangle with indices {i1}, {i2}, {i3}')
721
+ return result
722
+
701
723
 
702
724
  def update(self) -> None:
703
725
  ## First Edges
emerge/_emerge/mesher.py CHANGED
@@ -15,12 +15,12 @@
15
15
  # along with this program; if not, see
16
16
  # <https://www.gnu.org/licenses/>.
17
17
 
18
- import gmsh
18
+ import gmsh # type: ignore
19
19
  from .geometry import GeoVolume, GeoObject, GeoSurface
20
20
  from .selection import Selection, FaceSelection
21
21
  from .periodic import PeriodicCell
22
22
  import numpy as np
23
- from typing import Iterable, Callable
23
+ from typing import Iterable, Callable, Any, TypeVar
24
24
  from loguru import logger
25
25
  from enum import Enum
26
26
  from .bc import Periodic
@@ -55,7 +55,9 @@ _DOM_TO_STR = {
55
55
  2: "face",
56
56
  3: "volume",
57
57
  }
58
- def unpack_lists(_list: list[list], collector: list = None) -> list:
58
+
59
+ T = TypeVar('T')
60
+ def unpack_lists(_list: Any, collector: list | None = None) -> list[Any]:
59
61
  '''Unpack a recursive list of lists'''
60
62
  if collector is None:
61
63
  collector = []
@@ -116,7 +118,7 @@ class Mesher:
116
118
  raise MeshError('Either maximum or minimum mesh size is undefined. Make sure \
117
119
  to set the simulation frequency range before calling mesh instructions.')
118
120
 
119
- def submit_objects(self, objects: list[GeoObject]) -> None:
121
+ def submit_objects(self, objects: GeoObject | list[GeoObject] | list[list[GeoObject]]) -> None:
120
122
  """Takes al ist of GeoObjects and computes the fragment.
121
123
 
122
124
  Args:
@@ -126,16 +128,15 @@ class Mesher:
126
128
  objects = [objects,]
127
129
 
128
130
  objects = unpack_lists(objects)
129
- embeddings = []
130
-
131
+ embeddings: list = []
131
132
  gmsh.model.occ.synchronize()
132
133
 
133
- final_dimtags = unpack_lists([domain.dimtags for domain in objects])
134
+ final_dimtags = unpack_lists([domain.dimtags for domain in objects]) # type: ignore
134
135
 
135
136
  dom_mapping = dict()
136
- for dom in objects:
137
- embeddings.extend(dom._embeddings)
138
- for dt in dom.dimtags:
137
+ for dom in objects: # type: ignore
138
+ embeddings.extend(dom._embeddings) # type: ignore
139
+ for dt in dom.dimtags: # type: ignore
139
140
  dom_mapping[dt] = dom
140
141
 
141
142
 
@@ -145,24 +146,24 @@ class Mesher:
145
146
  1: dict(),
146
147
  2: dict(),
147
148
  3: dict()}
148
- if len(objects) > 0:
149
+ if len(objects) > 0: # type: ignore
149
150
  dimtags, output_mapping = gmsh.model.occ.fragment(final_dimtags, embedding_dimtags)
150
151
 
151
152
  for domain, mapping in zip(final_dimtags + embedding_dimtags, output_mapping):
152
153
  tag_mapping[domain[0]][domain[1]] = [o[1] for o in mapping]
153
- for dom in objects:
154
- dom.update_tags(tag_mapping)
154
+ for dom in objects: # type: ignore
155
+ dom.update_tags(tag_mapping) # type: ignore
155
156
  else:
156
157
  dimtags = final_dimtags
157
158
 
158
- self.objects = objects
159
+ self.objects = objects # type: ignore
159
160
 
160
161
  gmsh.model.occ.synchronize()
161
162
 
162
163
  def _set_mesh_periodicity(self,
163
- face1: FaceSelection,
164
- face2: FaceSelection,
165
- lattice: tuple[float,float,float]):
164
+ face1: Selection,
165
+ face2: Selection,
166
+ lattice: np.ndarray):
166
167
  translation = [1,0,0,lattice[0],
167
168
  0,1,0,lattice[1],
168
169
  0,0,1,lattice[2],
@@ -175,7 +176,7 @@ class Mesher:
175
176
  for tag in obj.tags:
176
177
  gmsh.model.mesh.setAlgorithm(obj.dim, tag, algorithm.value)
177
178
 
178
- def set_periodic_cell(self, cell: PeriodicCell, excluded_faces: list[FaceSelection] = None):
179
+ def set_periodic_cell(self, cell: PeriodicCell, excluded_faces: Selection | None = None):
179
180
  """Sets the periodic cell information based on the PeriodicCell class object"""
180
181
  if excluded_faces is None:
181
182
  for f1, f2, lat in cell.cell_data():
@@ -243,10 +244,10 @@ class Mesher:
243
244
  for dimtag in dimtags:
244
245
  gmsh.model.mesh.setSizeFromBoundary(dimtag[0], dimtag[1], 0)
245
246
 
246
- def set_boundary_size(self, object: GeoSurface | FaceSelection,
247
+ def set_boundary_size(self, boundary: GeoSurface | FaceSelection | Iterable,
247
248
  size:float,
248
249
  growth_rate: float = 1.4,
249
- max_size: float = None):
250
+ max_size: float | None = None) -> None:
250
251
  """Refine the mesh size along the boundary of a conducting surface
251
252
 
252
253
  Args:
@@ -255,8 +256,12 @@ class Mesher:
255
256
  growth_rate (float, optional): _description_. Defaults to 1.1.
256
257
  max_size (float, optional): _description_. Defaults to None.
257
258
  """
259
+ if isinstance(boundary, Iterable):
260
+ for bound in boundary:
261
+ self.set_boundary_size(bound, size, growth_rate, max_size)
262
+ return
258
263
 
259
- dimtags = object.dimtags
264
+ dimtags = boundary.dimtags
260
265
 
261
266
  if max_size is None:
262
267
  self._check_ready()
@@ -27,7 +27,7 @@ ALL PAIRED NODES ARE NO LONGER VISITED
27
27
  """
28
28
 
29
29
  import numpy as np
30
- from numba import njit, f8, i8
30
+ from numba import njit, f8, i8 # type: ignore
31
31
 
32
32
 
33
33
  ############################################################
@@ -72,7 +72,7 @@ def link_coords(coords: np.ndarray, ids1: np.ndarray, ids2: np.ndarray, disp: np
72
72
  # MAIN PYTHON INTERFACE #
73
73
  ############################################################
74
74
 
75
- def pair_coordinates(coords: np.ndarray, ids1: list[int], ids2: list[int], disp: np.ndarray, dsmax: float) -> dict[int, int]:
75
+ def pair_coordinates(coords: np.ndarray, ids1: np.ndarray, ids2: np.ndarray, disp: np.ndarray, dsmax: float) -> dict[int, int]:
76
76
  """ This function finds the mapping between a total coordinate set and two lits of indices.
77
77
 
78
78
  The indices correspond to two faces that are identical but displaced (mesh centroids of periodic boundaries).