emerge 0.5.0__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.
- emerge/_emerge/bc.py +11 -8
- emerge/_emerge/cs.py +2 -2
- emerge/_emerge/elements/femdata.py +14 -14
- emerge/_emerge/elements/index_interp.py +1 -1
- emerge/_emerge/elements/ned2_interp.py +1 -1
- emerge/_emerge/elements/nedelec2.py +4 -4
- emerge/_emerge/elements/nedleg2.py +9 -9
- emerge/_emerge/geo/horn.py +1 -1
- emerge/_emerge/geo/modeler.py +18 -19
- emerge/_emerge/geo/operations.py +13 -10
- emerge/_emerge/geo/pcb.py +70 -69
- emerge/_emerge/geo/pcb_tools/macro.py +14 -13
- emerge/_emerge/geo/pmlbox.py +1 -1
- emerge/_emerge/geometry.py +46 -32
- emerge/_emerge/logsettings.py +3 -3
- emerge/_emerge/material.py +11 -11
- emerge/_emerge/mesh3d.py +81 -59
- emerge/_emerge/mesher.py +26 -21
- emerge/_emerge/mth/pairing.py +2 -2
- emerge/_emerge/periodic.py +34 -31
- emerge/_emerge/physics/microwave/adaptive_freq.py +14 -11
- emerge/_emerge/physics/microwave/assembly/assembler.py +61 -57
- emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +43 -8
- emerge/_emerge/physics/microwave/assembly/robinbc.py +5 -5
- emerge/_emerge/physics/microwave/microwave_3d.py +40 -20
- emerge/_emerge/physics/microwave/microwave_bc.py +114 -95
- emerge/_emerge/physics/microwave/microwave_data.py +33 -33
- emerge/_emerge/physics/microwave/simjob.py +12 -12
- emerge/_emerge/physics/microwave/sparam.py +12 -12
- emerge/_emerge/physics/microwave/touchstone.py +1 -1
- emerge/_emerge/plot/display.py +12 -6
- emerge/_emerge/plot/pyvista/display.py +44 -39
- emerge/_emerge/plot/pyvista/display_settings.py +1 -1
- emerge/_emerge/plot/simple_plots.py +15 -15
- emerge/_emerge/selection.py +35 -39
- emerge/_emerge/simmodel.py +29 -39
- emerge/_emerge/simulation_data.py +19 -14
- emerge/_emerge/solve_interfaces/pardiso_interface.py +24 -18
- emerge/_emerge/solver.py +52 -52
- emerge/lib.py +243 -243
- {emerge-0.5.0.dist-info → emerge-0.5.2.dist-info}/METADATA +1 -1
- emerge-0.5.2.dist-info/RECORD +81 -0
- emerge/_emerge/plot/grapher.py +0 -93
- emerge-0.5.0.dist-info/RECORD +0 -82
- {emerge-0.5.0.dist-info → emerge-0.5.2.dist-info}/WHEEL +0 -0
- {emerge-0.5.0.dist-info → emerge-0.5.2.dist-info}/entry_points.txt +0 -0
- {emerge-0.5.0.dist-info → emerge-0.5.2.dist-info}/licenses/LICENSE +0 -0
emerge/_emerge/material.py
CHANGED
|
@@ -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:
|
|
39
|
-
_fur:
|
|
37
|
+
_neff: float | None = None
|
|
38
|
+
_fer: Callable | None= None
|
|
39
|
+
_fur: Callable | None = None
|
|
40
40
|
color: str = "#BEBEBE"
|
|
41
|
-
_color_rgb: tuple[
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
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 =
|
|
93
|
-
self.n_i2t: dict =
|
|
94
|
-
self.n_t2i: dict =
|
|
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 =
|
|
98
|
-
self.tet_i2t: dict =
|
|
99
|
-
self.tet_t2i: dict =
|
|
100
|
-
self.centers: np.ndarray =
|
|
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 =
|
|
104
|
-
self.tri_i2t: dict =
|
|
105
|
-
self.tri_t2i: dict =
|
|
106
|
-
self.areas: np.ndarray =
|
|
107
|
-
self.tri_centers: np.ndarray =
|
|
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 =
|
|
111
|
-
self.edge_i2t: dict =
|
|
112
|
-
self.edge_t2i: dict =
|
|
113
|
-
self.edge_centers: np.ndarray =
|
|
114
|
-
self.edge_lengths: np.ndarray =
|
|
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 =
|
|
118
|
-
self.inv_tris: dict =
|
|
119
|
-
self.inv_tets: dict =
|
|
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 =
|
|
124
|
-
self.tet_to_edge_sign: np.ndarray =
|
|
125
|
-
self.tet_to_tri: np.ndarray =
|
|
126
|
-
self.tri_to_tet: np.ndarray =
|
|
127
|
-
self.tri_to_edge: np.ndarray =
|
|
128
|
-
self.tri_to_edge_sign: np.ndarray =
|
|
129
|
-
self.edge_to_tri: defaultdict =
|
|
130
|
-
self.node_to_edge: defaultdict =
|
|
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 =
|
|
135
|
-
self.edge_to_field: np.ndarray =
|
|
136
|
-
self.tri_to_field: np.ndarray =
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
470
|
-
|
|
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,
|
|
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) ->
|
|
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
|
|
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 =
|
|
625
|
-
self.edge_tris: np.ndarray =
|
|
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 =
|
|
629
|
-
self.areas: np.ndarray =
|
|
630
|
-
self.normals: np.ndarray =
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
164
|
-
face2:
|
|
165
|
-
lattice:
|
|
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:
|
|
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,
|
|
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 =
|
|
264
|
+
dimtags = boundary.dimtags
|
|
260
265
|
|
|
261
266
|
if max_size is None:
|
|
262
267
|
self._check_ready()
|
emerge/_emerge/mth/pairing.py
CHANGED
|
@@ -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:
|
|
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).
|