emerge 0.5.2__py3-none-any.whl → 0.5.4__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 +2 -2
- emerge/_emerge/__init__.py +1 -26
- emerge/_emerge/_cache_check.py +46 -0
- emerge/_emerge/bc.py +3 -12
- emerge/_emerge/const.py +5 -0
- emerge/_emerge/elements/nedleg2.py +2 -2
- emerge/_emerge/geo/pcb.py +110 -13
- emerge/_emerge/geo/pcb_tools/calculator.py +2 -2
- emerge/_emerge/geometry.py +1 -1
- emerge/_emerge/logsettings.py +29 -13
- emerge/_emerge/material.py +4 -0
- emerge/_emerge/mesh3d.py +9 -9
- emerge/_emerge/mth/integrals.py +1 -1
- emerge/_emerge/mth/pairing.py +1 -2
- emerge/_emerge/periodic.py +1 -1
- emerge/_emerge/physics/microwave/adaptive_freq.py +1 -5
- emerge/_emerge/physics/microwave/assembly/assembler.py +62 -39
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +1 -8
- emerge/_emerge/physics/microwave/microwave_3d.py +33 -26
- emerge/_emerge/physics/microwave/microwave_bc.py +97 -27
- emerge/_emerge/physics/microwave/microwave_data.py +3 -5
- emerge/_emerge/physics/microwave/sc.py +26 -26
- emerge/_emerge/physics/microwave/simjob.py +8 -3
- emerge/_emerge/selection.py +1 -1
- emerge/_emerge/simmodel.py +12 -9
- emerge/_emerge/simulation_data.py +5 -1
- emerge/_emerge/solve_interfaces/cudss_interface.py +238 -0
- emerge/_emerge/solver.py +285 -107
- emerge/cli.py +1 -1
- emerge/lib.py +54 -40
- {emerge-0.5.2.dist-info → emerge-0.5.4.dist-info}/METADATA +15 -8
- {emerge-0.5.2.dist-info → emerge-0.5.4.dist-info}/RECORD +35 -32
- {emerge-0.5.2.dist-info → emerge-0.5.4.dist-info}/licenses/LICENSE +39 -0
- {emerge-0.5.2.dist-info → emerge-0.5.4.dist-info}/WHEEL +0 -0
- {emerge-0.5.2.dist-info → emerge-0.5.4.dist-info}/entry_points.txt +0 -0
|
@@ -27,6 +27,8 @@ from dataclasses import dataclass
|
|
|
27
27
|
from collections import defaultdict
|
|
28
28
|
from ...bc import BoundaryCondition, BoundaryConditionSet, Periodic
|
|
29
29
|
from ...periodic import PeriodicCell, HexCell, RectCell
|
|
30
|
+
from ...material import Material
|
|
31
|
+
from ...const import Z0, C0, PI, EPS0, MU0
|
|
30
32
|
|
|
31
33
|
class MWBoundaryConditionSet(BoundaryConditionSet):
|
|
32
34
|
|
|
@@ -39,13 +41,28 @@ class MWBoundaryConditionSet(BoundaryConditionSet):
|
|
|
39
41
|
self.ModalPort: type[ModalPort] = self._construct_bc(ModalPort)
|
|
40
42
|
self.LumpedPort: type[LumpedPort] = self._construct_bc(LumpedPort)
|
|
41
43
|
self.LumpedElement: type[LumpedElement] = self._construct_bc(LumpedElement)
|
|
44
|
+
self.SurfaceImpedance: type[SurfaceImpedance] = self._construct_bc(SurfaceImpedance)
|
|
42
45
|
self.RectangularWaveguide: type[RectangularWaveguide] = self._construct_bc(RectangularWaveguide)
|
|
43
46
|
self.Periodic: type[Periodic] = self._construct_bc(Periodic)
|
|
44
47
|
self.FloquetPort: type[FloquetPort] = self._construct_bc(FloquetPort)
|
|
45
48
|
|
|
46
49
|
self._cell: PeriodicCell | None = None
|
|
47
50
|
|
|
48
|
-
def
|
|
51
|
+
def get_conductors(self) -> list[BoundaryCondition]:
|
|
52
|
+
"""Returns a list of all boundary conditions that ought to be considered as a "conductor"
|
|
53
|
+
for the purpose of modal analyses.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
list[BoundaryCondition]: All conductor like boundary conditions
|
|
57
|
+
"""
|
|
58
|
+
bcs = self.oftype(PEC)
|
|
59
|
+
for bc in self.oftype(SurfaceImpedance):
|
|
60
|
+
if bc.material.cond > 1e3:
|
|
61
|
+
bcs.append(bc)
|
|
62
|
+
|
|
63
|
+
return bcs
|
|
64
|
+
|
|
65
|
+
def get_type(self, bctype: Literal['PEC','ModalPort','LumpedPort','PMC','LumpedElement','RectangularWaveguide','Periodic','FloquetPort','SurfaceImpedance']) -> FaceSelection:
|
|
49
66
|
tags = []
|
|
50
67
|
for bc in self.boundary_conditions:
|
|
51
68
|
if bctype in str(bc.__class__):
|
|
@@ -119,7 +136,7 @@ class RobinBC(BoundaryCondition):
|
|
|
119
136
|
raise NotImplementedError('get_Uinc not implemented for Port class')
|
|
120
137
|
|
|
121
138
|
class PortBC(RobinBC):
|
|
122
|
-
Zvac: float =
|
|
139
|
+
Zvac: float = Z0
|
|
123
140
|
def __init__(self, face: FaceSelection | GeoSurface):
|
|
124
141
|
"""(DO NOT USE) A generalization of the Port boundary condition.
|
|
125
142
|
|
|
@@ -165,9 +182,9 @@ class PortBC(RobinBC):
|
|
|
165
182
|
if self.modetype(k0)=='TEM':
|
|
166
183
|
return self.Zvac
|
|
167
184
|
elif self.modetype(k0)=='TE':
|
|
168
|
-
return k0*299792458/self.get_beta(k0) *
|
|
185
|
+
return k0*299792458/self.get_beta(k0) * MU0
|
|
169
186
|
elif self.modetype(k0)=='TM':
|
|
170
|
-
return self.get_beta(k0)/(k0*299792458*
|
|
187
|
+
return self.get_beta(k0)/(k0*299792458*EPS0)
|
|
171
188
|
else:
|
|
172
189
|
raise ValueError(f'Port mode type should be TEM, TE or TM but instead is {self.modetype(k0)}')
|
|
173
190
|
|
|
@@ -183,7 +200,7 @@ class PortBC(RobinBC):
|
|
|
183
200
|
Returns:
|
|
184
201
|
float: The mode amplitude correction factor.
|
|
185
202
|
"""
|
|
186
|
-
return np.sqrt(self.Zmode(k0)/
|
|
203
|
+
return np.sqrt(self.Zmode(k0)/Z0)
|
|
187
204
|
|
|
188
205
|
@property
|
|
189
206
|
def mode_number(self) -> int:
|
|
@@ -300,7 +317,7 @@ class PortMode:
|
|
|
300
317
|
|
|
301
318
|
def set_power(self, power: complex) -> None:
|
|
302
319
|
self.norm_factor = np.sqrt(1/np.abs(power))
|
|
303
|
-
logger.info(f'Setting port mode amplitude to: {self.norm_factor} ')
|
|
320
|
+
logger.info(f'Setting port mode amplitude to: {self.norm_factor:.2f} ')
|
|
304
321
|
|
|
305
322
|
class FloquetPort(PortBC):
|
|
306
323
|
_include_stiff: bool = True
|
|
@@ -334,7 +351,7 @@ class FloquetPort(PortBC):
|
|
|
334
351
|
self.cs = GCS
|
|
335
352
|
|
|
336
353
|
def portZ0(self, k0: float | None = None) -> complex | float | None:
|
|
337
|
-
return
|
|
354
|
+
return Z0
|
|
338
355
|
|
|
339
356
|
def get_amplitude(self, k0: float) -> float:
|
|
340
357
|
return 1.0
|
|
@@ -372,7 +389,7 @@ class FloquetPort(PortBC):
|
|
|
372
389
|
P = self.pol_p
|
|
373
390
|
S = self.pol_s
|
|
374
391
|
|
|
375
|
-
E0 = self.get_amplitude(k0)*np.sqrt(2*
|
|
392
|
+
E0 = self.get_amplitude(k0)*np.sqrt(2*Z0/(self.area))
|
|
376
393
|
Ex = E0*(-S*np.sin(self.scan_phi) - P*np.cos(self.scan_theta)*np.cos(self.scan_phi))*phi
|
|
377
394
|
Ey = E0*(S*np.cos(self.scan_phi) - P*np.cos(self.scan_theta)*np.sin(self.scan_phi))*phi
|
|
378
395
|
Ez = E0*(-P*E0*np.sin(self.scan_theta))*phi
|
|
@@ -646,13 +663,13 @@ class RectangularWaveguide(PortBC):
|
|
|
646
663
|
return self.cs._basis_inv
|
|
647
664
|
|
|
648
665
|
def portZ0(self, k0: float) -> complex:
|
|
649
|
-
return k0*299792458 *
|
|
666
|
+
return k0*299792458 * MU0/self.get_beta(k0)
|
|
650
667
|
|
|
651
668
|
def modetype(self, k0):
|
|
652
669
|
return self.type
|
|
653
670
|
|
|
654
671
|
def get_amplitude(self, k0: float) -> float:
|
|
655
|
-
Zte =
|
|
672
|
+
Zte = Z0
|
|
656
673
|
amplitude= np.sqrt(self.power*4*Zte/(self.dims[0]*self.dims[1]))
|
|
657
674
|
return amplitude
|
|
658
675
|
|
|
@@ -807,10 +824,10 @@ class LumpedPort(PortBC):
|
|
|
807
824
|
Returns:
|
|
808
825
|
complex: The γ-constant
|
|
809
826
|
"""
|
|
810
|
-
return 1j*k0*
|
|
827
|
+
return 1j*k0*Z0/self.surfZ
|
|
811
828
|
|
|
812
829
|
def get_Uinc(self, x_local, y_local, k0) -> np.ndarray:
|
|
813
|
-
Emag = -1j*2*k0 * self.voltage/self.height * (
|
|
830
|
+
Emag = -1j*2*k0 * self.voltage/self.height * (Z0/self.surfZ)
|
|
814
831
|
return Emag*self.port_mode_3d(x_local, y_local, k0)
|
|
815
832
|
|
|
816
833
|
def port_mode_3d(self,
|
|
@@ -899,16 +916,9 @@ class LumpedElement(RobinBC):
|
|
|
899
916
|
self.Z0: Callable = impedance_function # type: ignore
|
|
900
917
|
self.width: float = width # type: ignore
|
|
901
918
|
self.height: float = height # type: ignore
|
|
902
|
-
|
|
903
|
-
logger.info('Constructing coordinate system from normal port')
|
|
904
|
-
self.cs = Axis(self.selection.normal).construct_cs() # type: ignore
|
|
905
|
-
|
|
906
|
-
self.vintline: Line | None = None
|
|
907
|
-
self.v_integration = True
|
|
908
|
-
self.iintline: Line | None = None
|
|
909
919
|
|
|
910
920
|
def surfZ(self, k0: float) -> float:
|
|
911
|
-
"""The surface sheet impedance for the lumped
|
|
921
|
+
"""The surface sheet impedance for the lumped Element
|
|
912
922
|
|
|
913
923
|
Returns:
|
|
914
924
|
float: The surface sheet impedance
|
|
@@ -916,18 +926,17 @@ class LumpedElement(RobinBC):
|
|
|
916
926
|
Z0 = self.Z0(k0*299792458/(2*np.pi))*self.width/self.height
|
|
917
927
|
return Z0
|
|
918
928
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
return self.cs._basis
|
|
929
|
+
def get_basis(self) -> np.ndarray | None:
|
|
930
|
+
return None
|
|
922
931
|
|
|
923
|
-
def get_inv_basis(self) -> np.ndarray:
|
|
924
|
-
return
|
|
932
|
+
def get_inv_basis(self) -> np.ndarray | None:
|
|
933
|
+
return None
|
|
925
934
|
|
|
926
935
|
def get_beta(self, k0: float) -> float:
|
|
927
936
|
''' Return the out of plane propagation constant. βz.'''
|
|
928
937
|
|
|
929
938
|
return k0
|
|
930
|
-
|
|
939
|
+
|
|
931
940
|
def get_gamma(self, k0: float) -> complex:
|
|
932
941
|
"""Computes the γ-constant for matrix assembly. This constant is required for the Robin boundary condition.
|
|
933
942
|
|
|
@@ -937,6 +946,67 @@ class LumpedElement(RobinBC):
|
|
|
937
946
|
Returns:
|
|
938
947
|
complex: The γ-constant
|
|
939
948
|
"""
|
|
940
|
-
return 1j*k0*
|
|
949
|
+
return 1j*k0*Z0/self.surfZ(k0)
|
|
950
|
+
|
|
941
951
|
|
|
942
952
|
|
|
953
|
+
class SurfaceImpedance(RobinBC):
|
|
954
|
+
|
|
955
|
+
_include_stiff: bool = True
|
|
956
|
+
_include_mass: bool = False
|
|
957
|
+
_include_force: bool = False
|
|
958
|
+
|
|
959
|
+
def __init__(self,
|
|
960
|
+
face: FaceSelection | GeoSurface,
|
|
961
|
+
material: Material | None = None,
|
|
962
|
+
):
|
|
963
|
+
"""Generates a lumped power boundary condition.
|
|
964
|
+
|
|
965
|
+
The lumped port boundary condition assumes a uniform E-field along the "direction" axis.
|
|
966
|
+
The port with and height must be provided manually in meters. The height is the size
|
|
967
|
+
in the "direction" axis along which the potential is imposed. The width dimension
|
|
968
|
+
is orthogonal to that. For a rectangular face its the width and for a cyllindrical face
|
|
969
|
+
its the circumpherance.
|
|
970
|
+
|
|
971
|
+
Args:
|
|
972
|
+
face (FaceSelection, GeoSurface): The port surface
|
|
973
|
+
port_number (int): The port number
|
|
974
|
+
width (float): The port width (meters).
|
|
975
|
+
height (float): The port height (meters).
|
|
976
|
+
direction (Axis): The port direction as an Axis object (em.Axis(..) or em.ZAX)
|
|
977
|
+
active (bool, optional): Whether the port is active. Defaults to False.
|
|
978
|
+
power (float, optional): The port output power. Defaults to 1.
|
|
979
|
+
Z0 (float, optional): The port impedance. Defaults to 50.
|
|
980
|
+
"""
|
|
981
|
+
super().__init__(face)
|
|
982
|
+
|
|
983
|
+
self.material: Material = material
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
def get_basis(self) -> np.ndarray | None:
|
|
987
|
+
return None
|
|
988
|
+
|
|
989
|
+
def get_inv_basis(self) -> np.ndarray | None:
|
|
990
|
+
return None
|
|
991
|
+
|
|
992
|
+
def get_beta(self, k0: float) -> float:
|
|
993
|
+
''' Return the out of plane propagation constant. βz.'''
|
|
994
|
+
|
|
995
|
+
return k0
|
|
996
|
+
|
|
997
|
+
def get_gamma(self, k0: float) -> complex:
|
|
998
|
+
"""Computes the γ-constant for matrix assembly. This constant is required for the Robin boundary condition.
|
|
999
|
+
|
|
1000
|
+
Args:
|
|
1001
|
+
k0 (float): The free space propagation constant.
|
|
1002
|
+
|
|
1003
|
+
Returns:
|
|
1004
|
+
complex: The γ-constant
|
|
1005
|
+
"""
|
|
1006
|
+
w0 = k0*C0
|
|
1007
|
+
sigma = self.material.cond
|
|
1008
|
+
rho = 1/sigma
|
|
1009
|
+
d_skin = (2*rho/(w0*MU0) * ((1+(w0*EPS0*rho)**2)**0.5 + rho*w0*EPS0))**0.5
|
|
1010
|
+
d_skin = (2*rho/(w0*MU0))**0.5
|
|
1011
|
+
R = rho/d_skin
|
|
1012
|
+
return 1j*k0*Z0/R
|
|
@@ -27,6 +27,7 @@ from ...cs import Axis, _parse_axis
|
|
|
27
27
|
from ...selection import FaceSelection
|
|
28
28
|
from ...geometry import GeoSurface
|
|
29
29
|
from ...mesh3d import Mesh3D
|
|
30
|
+
from ...const import Z0, MU0, EPS0
|
|
30
31
|
|
|
31
32
|
EMField = Literal[
|
|
32
33
|
"er", "ur", "freq", "k0",
|
|
@@ -36,9 +37,6 @@ EMField = Literal[
|
|
|
36
37
|
"mode", "beta",
|
|
37
38
|
]
|
|
38
39
|
|
|
39
|
-
EPS0 = 8.854187818814e-12
|
|
40
|
-
MU0 = 1.2566370612720e-6
|
|
41
|
-
|
|
42
40
|
def arc_on_plane(ref_dir, normal, angle_range_deg, num_points=100):
|
|
43
41
|
"""
|
|
44
42
|
Generate theta/phi coordinates of an arc on a plane.
|
|
@@ -297,7 +295,7 @@ class FarfieldData:
|
|
|
297
295
|
logger.warning('Defaulting to normE')
|
|
298
296
|
F = np.sqrt(np.abs(self.E[0,:])**2 + np.abs(self.E[1,:])**2 + np.abs(self.E[2,:])**2)
|
|
299
297
|
if isotropic:
|
|
300
|
-
F = F/np.sqrt(
|
|
298
|
+
F = F/np.sqrt(Z0/(2*np.pi))
|
|
301
299
|
if dB:
|
|
302
300
|
F = 20*np.log10(np.clip(np.abs(F), a_min=10**(dBfloor/20), a_max = 1e9))-dBfloor
|
|
303
301
|
if rmax is not None:
|
|
@@ -662,7 +660,7 @@ class MWField:
|
|
|
662
660
|
self.Ez = Ez.reshape(shp)
|
|
663
661
|
|
|
664
662
|
|
|
665
|
-
constants = 1/ (-1j*2*np.pi*self.freq*(self._dur*
|
|
663
|
+
constants = 1/ (-1j*2*np.pi*self.freq*(self._dur*MU0) )
|
|
666
664
|
Hx, Hy, Hz = self.basis.interpolate_curl(self._field, xf, yf, zf, constants)
|
|
667
665
|
ids = self.basis.interpolate_index(xf, yf, zf)
|
|
668
666
|
self.er = self._der[ids].reshape(shp)
|
|
@@ -19,19 +19,21 @@ from numba_progress import ProgressBar
|
|
|
19
19
|
from ...mesh3d import SurfaceMesh
|
|
20
20
|
import numpy as np
|
|
21
21
|
from loguru import logger
|
|
22
|
-
from numba import
|
|
23
|
-
from numba.types import Tuple as TupleType
|
|
22
|
+
from numba import c16, njit, prange, f8
|
|
23
|
+
from numba.types import Tuple as TupleType # ty: ignore
|
|
24
24
|
from numba_progress.progress import ProgressBarType
|
|
25
|
+
from ...const import Z0
|
|
25
26
|
|
|
26
27
|
LR = 0.001
|
|
28
|
+
|
|
27
29
|
@njit(
|
|
28
|
-
TupleType((
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
TupleType((c16[:, :], c16[:, :]))(
|
|
31
|
+
c16[:, :],
|
|
32
|
+
c16[:, :],
|
|
33
|
+
f8[:, :],
|
|
34
|
+
f8[:, :],
|
|
35
|
+
f8[:, :],
|
|
36
|
+
f8,
|
|
35
37
|
ProgressBarType,
|
|
36
38
|
),
|
|
37
39
|
parallel=True,
|
|
@@ -86,17 +88,15 @@ def stratton_chu_ff(Ein, Hin, vis, wns, tpout, k0, pgb):
|
|
|
86
88
|
|
|
87
89
|
N = tpout.shape[1]
|
|
88
90
|
|
|
89
|
-
Eout = np.zeros((3, N)).astype(np.
|
|
90
|
-
Hout = np.zeros((3, N)).astype(np.
|
|
91
|
-
|
|
92
|
-
Eoutx = np.zeros((N,)).astype(np.complex64)
|
|
93
|
-
Eouty = np.zeros((N,)).astype(np.complex64)
|
|
94
|
-
Eoutz = np.zeros((N,)).astype(np.complex64)
|
|
91
|
+
Eout = np.zeros((3, N)).astype(np.complex128)
|
|
92
|
+
Hout = np.zeros((3, N)).astype(np.complex128)
|
|
95
93
|
|
|
96
|
-
|
|
94
|
+
Eoutx = np.zeros((N,)).astype(np.complex128)
|
|
95
|
+
Eouty = np.zeros((N,)).astype(np.complex128)
|
|
96
|
+
Eoutz = np.zeros((N,)).astype(np.complex128)
|
|
97
97
|
|
|
98
|
-
Q = np.
|
|
99
|
-
ii = np.
|
|
98
|
+
Q = np.complex128(-1j * k0 / (4 * np.pi))
|
|
99
|
+
ii = np.complex128(1j)
|
|
100
100
|
|
|
101
101
|
NxHx = ny * Hz - nz * Hy
|
|
102
102
|
NxHy = nz * Hx - nx * Hz
|
|
@@ -106,7 +106,7 @@ def stratton_chu_ff(Ein, Hin, vis, wns, tpout, k0, pgb):
|
|
|
106
106
|
NxEy = nz * Ex - nx * Ez
|
|
107
107
|
NxEz = nx * Ey - ny * Ex
|
|
108
108
|
|
|
109
|
-
for j in prange(Nids):
|
|
109
|
+
for j in prange(Nids): # ty: ignore
|
|
110
110
|
xi = vx[j]
|
|
111
111
|
yi = vy[j]
|
|
112
112
|
zi = vz[j]
|
|
@@ -147,7 +147,7 @@ def stratton_chu(Ein, Hin, mesh: SurfaceMesh, theta: np.ndarray, phi: np.ndarray
|
|
|
147
147
|
areas = mesh.areas
|
|
148
148
|
vis = mesh.edge_centers
|
|
149
149
|
|
|
150
|
-
wns = np.zeros_like(vis).astype(np.
|
|
150
|
+
wns = np.zeros_like(vis).astype(np.float64)
|
|
151
151
|
|
|
152
152
|
tri_normals = mesh.normals
|
|
153
153
|
tri_ids = mesh.tri_to_edge
|
|
@@ -164,12 +164,12 @@ def stratton_chu(Ein, Hin, mesh: SurfaceMesh, theta: np.ndarray, phi: np.ndarray
|
|
|
164
164
|
tpout = np.array([theta, phi])
|
|
165
165
|
with ProgressBar(total=Ntot, ncols=100, dynamic_ncols=False) as pgb:
|
|
166
166
|
Eout, Hout = stratton_chu_ff(
|
|
167
|
-
Ein.astype(np.
|
|
168
|
-
Hin.astype(np.
|
|
169
|
-
vis.astype(np.
|
|
170
|
-
wns.astype(np.
|
|
171
|
-
tpout.astype(np.
|
|
172
|
-
np.
|
|
167
|
+
Ein.astype(np.complex128),
|
|
168
|
+
Hin.astype(np.complex128),
|
|
169
|
+
vis.astype(np.float64),
|
|
170
|
+
wns.astype(np.float64),
|
|
171
|
+
tpout.astype(np.float64),
|
|
172
|
+
np.float64(k0),
|
|
173
173
|
pgb,
|
|
174
174
|
)
|
|
175
175
|
return Eout.astype(np.complex128), Hout.astype(np.complex128)
|
|
@@ -27,7 +27,7 @@ class SimJob:
|
|
|
27
27
|
b: np.ndarray | None,
|
|
28
28
|
freq: float,
|
|
29
29
|
cache_factorization: bool,
|
|
30
|
-
B: csr_matrix = None
|
|
30
|
+
B: csr_matrix | None = None
|
|
31
31
|
):
|
|
32
32
|
|
|
33
33
|
self.A: csr_matrix = A
|
|
@@ -88,15 +88,20 @@ class SimJob:
|
|
|
88
88
|
|
|
89
89
|
b_active = self.b + mode
|
|
90
90
|
A = self.load_if_needed('A')
|
|
91
|
-
|
|
91
|
+
|
|
92
|
+
aux = {
|
|
93
|
+
'Active port': str(key),
|
|
94
|
+
}
|
|
92
95
|
|
|
93
96
|
if self.has_periodic:
|
|
94
97
|
P = self.load_if_needed('P')
|
|
95
98
|
Pd = self.load_if_needed('Pd')
|
|
96
99
|
b_active = Pd @ b_active
|
|
97
100
|
A = Pd @ A @ P
|
|
101
|
+
aux['Periodic reduction'] = str(P.shape)
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
|
|
104
|
+
yield A, b_active, self.solve_ids, reuse_factorization, aux
|
|
100
105
|
|
|
101
106
|
reuse_factorization = True
|
|
102
107
|
|
emerge/_emerge/selection.py
CHANGED
|
@@ -536,7 +536,7 @@ class Selector:
|
|
|
536
536
|
nx: float,
|
|
537
537
|
ny: float,
|
|
538
538
|
nz: float,
|
|
539
|
-
tolerance: float = 1e-
|
|
539
|
+
tolerance: float = 1e-8) -> FaceSelection:
|
|
540
540
|
"""Returns a FaceSelection for all faces that lie in a provided infinite plane
|
|
541
541
|
specified by an origin plus a plane normal vector.
|
|
542
542
|
|
emerge/_emerge/simmodel.py
CHANGED
|
@@ -51,11 +51,9 @@ Known problems/solutions:
|
|
|
51
51
|
--------------------------
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
-
|
|
55
54
|
class SimulationError(Exception):
|
|
56
55
|
pass
|
|
57
56
|
|
|
58
|
-
|
|
59
57
|
############################################################
|
|
60
58
|
# BASE 3D SIMULATION MODEL #
|
|
61
59
|
############################################################
|
|
@@ -93,7 +91,6 @@ class Simulation3D:
|
|
|
93
91
|
|
|
94
92
|
self.mesh: Mesh3D = Mesh3D(self.mesher)
|
|
95
93
|
self.select: Selector = Selector()
|
|
96
|
-
self.set_loglevel(loglevel)
|
|
97
94
|
|
|
98
95
|
## STATES
|
|
99
96
|
self.__active: bool = False
|
|
@@ -102,9 +99,6 @@ class Simulation3D:
|
|
|
102
99
|
|
|
103
100
|
self.display: PVDisplay = PVDisplay(self.mesh)
|
|
104
101
|
|
|
105
|
-
if logfile:
|
|
106
|
-
self.set_logfile()
|
|
107
|
-
|
|
108
102
|
self.save_file: bool = save_file
|
|
109
103
|
self.load_file: bool = load_file
|
|
110
104
|
|
|
@@ -115,6 +109,10 @@ class Simulation3D:
|
|
|
115
109
|
|
|
116
110
|
self._initialize_simulation()
|
|
117
111
|
|
|
112
|
+
self.set_loglevel(loglevel)
|
|
113
|
+
if logfile:
|
|
114
|
+
self.set_logfile()
|
|
115
|
+
|
|
118
116
|
self._update_data()
|
|
119
117
|
|
|
120
118
|
|
|
@@ -286,6 +284,8 @@ class Simulation3D:
|
|
|
286
284
|
loglevel ('DEBUG','INFO','WARNING','ERROR'): The loglevel
|
|
287
285
|
"""
|
|
288
286
|
LOG_CONTROLLER.set_std_loglevel(loglevel)
|
|
287
|
+
if loglevel not in ('TRACE','DEBUG'):
|
|
288
|
+
gmsh.option.setNumber("General.Terminal", 0)
|
|
289
289
|
|
|
290
290
|
def set_logfile(self) -> None:
|
|
291
291
|
"""Adds a file output for the logger."""
|
|
@@ -318,7 +318,6 @@ class Simulation3D:
|
|
|
318
318
|
|
|
319
319
|
return None
|
|
320
320
|
|
|
321
|
-
|
|
322
321
|
def set_periodic_cell(self, cell: PeriodicCell, excluded_faces: list[FaceSelection] | None = None):
|
|
323
322
|
"""Set the given periodic cell object as the simulations peridicity.
|
|
324
323
|
|
|
@@ -332,7 +331,7 @@ class Simulation3D:
|
|
|
332
331
|
def commit_geometry(self, *geometries: GeoObject | list[GeoObject]) -> None:
|
|
333
332
|
"""Finalizes and locks the current geometry state of the simulation.
|
|
334
333
|
|
|
335
|
-
The geometries may be provided (legacy behavior) but are automatically managed
|
|
334
|
+
The geometries may be provided (legacy behavior) but are automatically managed in the background.
|
|
336
335
|
|
|
337
336
|
"""
|
|
338
337
|
geometries_parsed: Any = None
|
|
@@ -375,12 +374,16 @@ class Simulation3D:
|
|
|
375
374
|
self.mesher.set_mesh_size(self.mw.get_discretizer(), self.mw.resolution)
|
|
376
375
|
|
|
377
376
|
try:
|
|
377
|
+
gmsh.logger.start()
|
|
378
378
|
gmsh.model.mesh.generate(3)
|
|
379
|
+
logs = gmsh.logger.get()
|
|
380
|
+
gmsh.logger.stop()
|
|
381
|
+
for log in logs:
|
|
382
|
+
logger.trace('[GMSH] '+log)
|
|
379
383
|
except Exception:
|
|
380
384
|
logger.error('GMSH Mesh error detected.')
|
|
381
385
|
print(_GMSH_ERROR_TEXT)
|
|
382
386
|
raise
|
|
383
|
-
|
|
384
387
|
self.mesh.update(self.mesher._get_periodic_bcs())
|
|
385
388
|
self.mesh.exterior_face_tags = self.mesher.domain_boundary_face_tags
|
|
386
389
|
gmsh.model.occ.synchronize()
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
import numpy as np
|
|
20
20
|
from loguru import logger
|
|
21
|
-
from typing import TypeVar, Generic, Any, List, Union, Dict
|
|
21
|
+
from typing import TypeVar, Generic, Any, List, Union, Dict, Generator
|
|
22
22
|
from collections import defaultdict
|
|
23
23
|
|
|
24
24
|
T = TypeVar("T")
|
|
@@ -187,6 +187,10 @@ class DataContainer:
|
|
|
187
187
|
self.entries.append(entry)
|
|
188
188
|
return entry
|
|
189
189
|
|
|
190
|
+
def iterate(self) -> Generator[tuple[dict[str, float], dict[str, Any]], None, None]:
|
|
191
|
+
for entry in self.entries:
|
|
192
|
+
yield entry.vars, entry.data
|
|
193
|
+
|
|
190
194
|
@property
|
|
191
195
|
def last(self) -> DataEntry:
|
|
192
196
|
"""Returns the last added entry"""
|