emerge 0.5.1__py3-none-any.whl → 0.5.3__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 +14 -20
- emerge/_emerge/const.py +5 -0
- 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 +10 -10
- 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 +180 -82
- emerge/_emerge/geo/pcb_tools/calculator.py +2 -2
- emerge/_emerge/geo/pcb_tools/macro.py +14 -13
- emerge/_emerge/geo/pmlbox.py +1 -1
- emerge/_emerge/geometry.py +47 -33
- emerge/_emerge/logsettings.py +15 -16
- emerge/_emerge/material.py +15 -11
- emerge/_emerge/mesh3d.py +81 -59
- emerge/_emerge/mesher.py +26 -21
- emerge/_emerge/mth/integrals.py +1 -1
- emerge/_emerge/mth/pairing.py +2 -2
- emerge/_emerge/periodic.py +34 -31
- emerge/_emerge/physics/microwave/adaptive_freq.py +15 -16
- emerge/_emerge/physics/microwave/assembly/assembler.py +120 -93
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +1 -8
- 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 +71 -44
- emerge/_emerge/physics/microwave/microwave_bc.py +206 -117
- emerge/_emerge/physics/microwave/microwave_data.py +36 -38
- emerge/_emerge/physics/microwave/sc.py +26 -26
- emerge/_emerge/physics/microwave/simjob.py +20 -15
- 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 +41 -47
- emerge/_emerge/simulation_data.py +24 -15
- emerge/_emerge/solve_interfaces/cudss_interface.py +238 -0
- emerge/_emerge/solve_interfaces/pardiso_interface.py +24 -18
- emerge/_emerge/solver.py +314 -136
- emerge/cli.py +1 -1
- emerge/lib.py +245 -248
- {emerge-0.5.1.dist-info → emerge-0.5.3.dist-info}/METADATA +5 -1
- emerge-0.5.3.dist-info/RECORD +83 -0
- emerge/_emerge/plot/grapher.py +0 -93
- emerge-0.5.1.dist-info/RECORD +0 -82
- {emerge-0.5.1.dist-info → emerge-0.5.3.dist-info}/WHEEL +0 -0
- {emerge-0.5.1.dist-info → emerge-0.5.3.dist-info}/entry_points.txt +0 -0
- {emerge-0.5.1.dist-info → emerge-0.5.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,13 +20,14 @@ from ...simulation_data import BaseDataset, DataContainer
|
|
|
20
20
|
from ...elements.femdata import FEMBasis
|
|
21
21
|
from dataclasses import dataclass
|
|
22
22
|
import numpy as np
|
|
23
|
-
from typing import Literal
|
|
23
|
+
from typing import Literal
|
|
24
24
|
from loguru import logger
|
|
25
25
|
from .adaptive_freq import SparamModel
|
|
26
26
|
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.
|
|
@@ -128,7 +126,7 @@ def generate_ndim(
|
|
|
128
126
|
outer_data: dict[str, list[float]],
|
|
129
127
|
inner_data: list[float],
|
|
130
128
|
outer_labels: tuple[str, ...]
|
|
131
|
-
) -> np.ndarray:
|
|
129
|
+
) -> tuple[np.ndarray,...]:
|
|
132
130
|
"""
|
|
133
131
|
Generates an N-dimensional grid of values from flattened data, and returns each axis array plus the grid.
|
|
134
132
|
|
|
@@ -231,10 +229,10 @@ class Sparam:
|
|
|
231
229
|
|
|
232
230
|
@dataclass
|
|
233
231
|
class PortProperties:
|
|
234
|
-
port_number: int
|
|
232
|
+
port_number: int = -1
|
|
235
233
|
k0: float | None= None
|
|
236
234
|
beta: float | None = None
|
|
237
|
-
Z0: float | None = None
|
|
235
|
+
Z0: float | complex | None = None
|
|
238
236
|
Pout: float | None = None
|
|
239
237
|
mode_number: int = 1
|
|
240
238
|
|
|
@@ -259,7 +257,7 @@ class FarfieldData:
|
|
|
259
257
|
|
|
260
258
|
def surfplot(self,
|
|
261
259
|
polarization: Literal['Ex','Ey','Ez','Etheta','Ephi','normE'],
|
|
262
|
-
isotropic: bool = True, dB: bool = False, dBfloor: float = -30, rmax: float = None,
|
|
260
|
+
isotropic: bool = True, dB: bool = False, dBfloor: float = -30, rmax: float | None = None,
|
|
263
261
|
offset: tuple[float, float, float] = (0,0,0)) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
264
262
|
"""Returns the parameters to be used as positional arguments for the display.add_surf() function.
|
|
265
263
|
|
|
@@ -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:
|
|
@@ -345,7 +343,7 @@ class EHField:
|
|
|
345
343
|
|
|
346
344
|
@property
|
|
347
345
|
def Dy(self) -> np.ndarray:
|
|
348
|
-
return self.
|
|
346
|
+
return self.Ey*self.er
|
|
349
347
|
|
|
350
348
|
@property
|
|
351
349
|
def Dz(self) -> np.ndarray:
|
|
@@ -499,16 +497,16 @@ class EHField:
|
|
|
499
497
|
Returns:
|
|
500
498
|
(X,Y,Z,Field): The coordinates plus field scalar
|
|
501
499
|
"""
|
|
502
|
-
|
|
500
|
+
field_arry = getattr(self, field)
|
|
503
501
|
if metric=='abs':
|
|
504
|
-
field = np.abs(
|
|
502
|
+
field = np.abs(field_arry)
|
|
505
503
|
elif metric=='real':
|
|
506
|
-
field =
|
|
504
|
+
field = field_arry.real
|
|
507
505
|
elif metric=='imag':
|
|
508
|
-
field =
|
|
506
|
+
field = field_arry.imag
|
|
509
507
|
elif metric=='complex':
|
|
510
|
-
field =
|
|
511
|
-
return self.x, self.y, self.z,
|
|
508
|
+
field = field_arry
|
|
509
|
+
return self.x, self.y, self.z, field_arry
|
|
512
510
|
|
|
513
511
|
class _EHSign:
|
|
514
512
|
"""A small class to manage the sign of field components when computing the far-field with Stratton-Chu
|
|
@@ -588,7 +586,7 @@ class MWField:
|
|
|
588
586
|
mode_number: int,
|
|
589
587
|
k0: float,
|
|
590
588
|
beta: float,
|
|
591
|
-
Z0: float,
|
|
589
|
+
Z0: float | complex | None,
|
|
592
590
|
Pout: float) -> None:
|
|
593
591
|
self.port_modes.append(PortProperties(port_number=port_number,
|
|
594
592
|
mode_number=mode_number,
|
|
@@ -609,7 +607,7 @@ class MWField:
|
|
|
609
607
|
def _field(self) -> np.ndarray:
|
|
610
608
|
if self._mode_field is not None:
|
|
611
609
|
return self._mode_field
|
|
612
|
-
return sum([self.excitation[mode.port_number]*self._fields[mode.port_number] for mode in self.port_modes])
|
|
610
|
+
return sum([self.excitation[mode.port_number]*self._fields[mode.port_number] for mode in self.port_modes]) # type: ignore
|
|
613
611
|
|
|
614
612
|
def set_field_vector(self) -> None:
|
|
615
613
|
"""Defines the default excitation coefficients for the current dataset"""
|
|
@@ -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)
|
|
@@ -678,9 +676,9 @@ class MWField:
|
|
|
678
676
|
|
|
679
677
|
def cutplane(self,
|
|
680
678
|
ds: float,
|
|
681
|
-
x: float=None,
|
|
682
|
-
y: float=None,
|
|
683
|
-
z: float=None) -> EHField:
|
|
679
|
+
x: float | None = None,
|
|
680
|
+
y: float | None = None,
|
|
681
|
+
z: float | None = None) -> EHField:
|
|
684
682
|
xb, yb, zb = self.basis.bounds
|
|
685
683
|
xs = np.linspace(xb[0], xb[1], int((xb[1]-xb[0])/ds))
|
|
686
684
|
ys = np.linspace(yb[0], yb[1], int((yb[1]-yb[0])/ds))
|
|
@@ -765,8 +763,8 @@ class MWField:
|
|
|
765
763
|
faces: FaceSelection | GeoSurface,
|
|
766
764
|
ang_range: tuple[float, float] = (-180, 180),
|
|
767
765
|
Npoints: int = 201,
|
|
768
|
-
origin: tuple[float, float, float] = None,
|
|
769
|
-
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] = None) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
766
|
+
origin: tuple[float, float, float] | None = None,
|
|
767
|
+
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] | None = None) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
770
768
|
"""Compute the farfield electric and magnetic field defined by a circle.
|
|
771
769
|
|
|
772
770
|
Args:
|
|
@@ -782,18 +780,18 @@ class MWField:
|
|
|
782
780
|
tuple[np.ndarray, np.ndarray, np.ndarray]: _description_
|
|
783
781
|
"""
|
|
784
782
|
refdir = _parse_axis(ref_direction).np
|
|
785
|
-
|
|
786
|
-
theta, phi = arc_on_plane(refdir,
|
|
783
|
+
plane_normal_parsed = _parse_axis(plane_normal).np
|
|
784
|
+
theta, phi = arc_on_plane(refdir, plane_normal_parsed, ang_range, Npoints)
|
|
787
785
|
E,H = self.farfield(theta, phi, faces, origin, syms = syms)
|
|
788
786
|
angs = np.linspace(*ang_range, Npoints)*np.pi/180
|
|
789
787
|
return angs, E ,H
|
|
790
788
|
|
|
791
789
|
def farfield_3d(self,
|
|
792
790
|
faces: FaceSelection | GeoSurface,
|
|
793
|
-
thetas: np.ndarray = None,
|
|
794
|
-
phis: np.ndarray = None,
|
|
795
|
-
origin: tuple[float, float, float] = None,
|
|
796
|
-
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] = None) -> FarfieldData:
|
|
791
|
+
thetas: np.ndarray | None = None,
|
|
792
|
+
phis: np.ndarray | None = None,
|
|
793
|
+
origin: tuple[float, float, float] | None = None,
|
|
794
|
+
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] | None = None) -> FarfieldData:
|
|
797
795
|
"""Compute the farfield in a 3D angular grid
|
|
798
796
|
|
|
799
797
|
If thetas and phis are not provided, they default to a sample space of 2 degrees.
|
|
@@ -823,8 +821,8 @@ class MWField:
|
|
|
823
821
|
def farfield(self, theta: np.ndarray,
|
|
824
822
|
phi: np.ndarray,
|
|
825
823
|
faces: FaceSelection | GeoSurface,
|
|
826
|
-
origin: tuple[float, float, float] = None,
|
|
827
|
-
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] = None) -> tuple[np.ndarray, np.ndarray]:
|
|
824
|
+
origin: tuple[float, float, float] | None = None,
|
|
825
|
+
syms: list[Literal['Ex','Ey','Ez', 'Hx','Hy','Hz']] | None = None) -> tuple[np.ndarray, np.ndarray]:
|
|
828
826
|
"""Compute the farfield at the provided theta/phi coordinates
|
|
829
827
|
|
|
830
828
|
Args:
|
|
@@ -874,7 +872,7 @@ class MWField:
|
|
|
874
872
|
|
|
875
873
|
return Eff, Hff
|
|
876
874
|
|
|
877
|
-
def optycal(self, faces: FaceSelection | GeoSurface = None) -> tuple:
|
|
875
|
+
def optycal(self, faces: FaceSelection | GeoSurface | None = None) -> tuple:
|
|
878
876
|
"""Export this models exterior to an Optical acceptable dataset
|
|
879
877
|
|
|
880
878
|
Args:
|
|
@@ -953,7 +951,7 @@ class MWScalar:
|
|
|
953
951
|
mode_number: int,
|
|
954
952
|
k0: float,
|
|
955
953
|
beta: float,
|
|
956
|
-
Z0: float,
|
|
954
|
+
Z0: float | complex,
|
|
957
955
|
Pout: float) -> None:
|
|
958
956
|
i = self._portmap[port_number]
|
|
959
957
|
self.beta[i] = beta
|
|
@@ -1026,9 +1024,9 @@ class MWScalarNdim:
|
|
|
1026
1024
|
|
|
1027
1025
|
def export_touchstone(self,
|
|
1028
1026
|
filename: str,
|
|
1029
|
-
Z0ref: float = None,
|
|
1027
|
+
Z0ref: float | None = None,
|
|
1030
1028
|
format: Literal['RI','MA','DB'] = 'RI',
|
|
1031
|
-
custom_comments: list[str] = None,
|
|
1029
|
+
custom_comments: list[str] | None = None,
|
|
1032
1030
|
funit: Literal['HZ','KHZ','MHZ','GHZ'] = 'GHZ'):
|
|
1033
1031
|
"""Export the S-parameter data to a touchstone file
|
|
1034
1032
|
|
|
@@ -1063,9 +1061,9 @@ class MWScalarNdim:
|
|
|
1063
1061
|
filename: str,
|
|
1064
1062
|
Smatrix: np.ndarray,
|
|
1065
1063
|
frequencies: np.ndarray,
|
|
1066
|
-
Z0ref: float = None,
|
|
1064
|
+
Z0ref: float | None = None,
|
|
1067
1065
|
format: Literal['RI','MA','DB'] = 'RI',
|
|
1068
|
-
custom_comments: list[str] = None,
|
|
1066
|
+
custom_comments: list[str] | None = None,
|
|
1069
1067
|
funit: Literal['HZ','KHZ','MHZ','GHZ'] = 'GHZ') -> None:
|
|
1070
1068
|
"""Save an S-parameter matrix to a touchstone file.
|
|
1071
1069
|
|
|
@@ -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)
|
|
@@ -17,39 +17,39 @@
|
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
19
|
import os
|
|
20
|
-
from scipy.sparse import csr_matrix, save_npz, load_npz
|
|
20
|
+
from scipy.sparse import csr_matrix, save_npz, load_npz # type: ignore
|
|
21
21
|
from ...solver import SolveReport
|
|
22
22
|
|
|
23
23
|
class SimJob:
|
|
24
24
|
|
|
25
25
|
def __init__(self,
|
|
26
26
|
A: csr_matrix,
|
|
27
|
-
b: np.ndarray,
|
|
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
|
|
34
|
-
self.B: csr_matrix = B
|
|
35
|
-
self.b: np.ndarray = b
|
|
36
|
-
self.P: csr_matrix = None
|
|
37
|
-
self.Pd: csr_matrix = None
|
|
34
|
+
self.B: csr_matrix | None = B
|
|
35
|
+
self.b: np.ndarray | None = b
|
|
36
|
+
self.P: csr_matrix | None= None
|
|
37
|
+
self.Pd: csr_matrix | None = None
|
|
38
38
|
self.has_periodic: bool = False
|
|
39
39
|
|
|
40
40
|
self.freq: float = freq
|
|
41
41
|
self.k0: float = 2*np.pi*freq/299792458
|
|
42
42
|
self.cache_factorization: bool = cache_factorization
|
|
43
43
|
self._fields: dict[int, np.ndarray] = dict()
|
|
44
|
-
self.port_vectors: dict = None
|
|
45
|
-
self.solve_ids = None
|
|
44
|
+
self.port_vectors: dict | None = None
|
|
45
|
+
self.solve_ids: np.ndarray | None = None
|
|
46
46
|
|
|
47
|
-
self.store_limit = None
|
|
48
|
-
self.relative_path = None
|
|
49
|
-
self._store_location = {}
|
|
47
|
+
self.store_limit: int | None = None
|
|
48
|
+
self.relative_path: str | None = None
|
|
49
|
+
self._store_location: dict = {}
|
|
50
50
|
self._stored: bool = False
|
|
51
51
|
|
|
52
|
-
self._active_port: int =
|
|
52
|
+
self._active_port: int = -1
|
|
53
53
|
self.reports: list[SolveReport] = []
|
|
54
54
|
self.id: int = -1
|
|
55
55
|
self.store_if_needed()
|
|
@@ -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
|
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
# along with this program; if not, see
|
|
16
16
|
# <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
|
-
from .microwave_bc import
|
|
18
|
+
from .microwave_bc import PortBC
|
|
19
19
|
from ...mth.integrals import surface_integral
|
|
20
20
|
import numpy as np
|
|
21
21
|
from typing import Callable
|
|
22
22
|
|
|
23
23
|
def sparam_waveport(nodes: np.ndarray,
|
|
24
24
|
tri_vertices: np.ndarray,
|
|
25
|
-
bc:
|
|
25
|
+
bc: PortBC,
|
|
26
26
|
freq: float,
|
|
27
27
|
fieldf: Callable,
|
|
28
28
|
ndpts: int = 4):
|
|
@@ -62,18 +62,18 @@ def sparam_waveport(nodes: np.ndarray,
|
|
|
62
62
|
Ex2, Ey2, Ez2 = modef_c(x,y,z)
|
|
63
63
|
return Ex1*Ex2 + Ey1*Ey2 + Ez1*Ez2
|
|
64
64
|
|
|
65
|
-
mode_dot_field = surface_integral(nodes, tri_vertices, inproduct1,
|
|
66
|
-
norm = surface_integral(nodes, tri_vertices, inproduct2,
|
|
65
|
+
mode_dot_field = surface_integral(nodes, tri_vertices, inproduct1, gq_order=ndpts)
|
|
66
|
+
norm = surface_integral(nodes, tri_vertices, inproduct2, gq_order=ndpts)
|
|
67
67
|
|
|
68
68
|
svec = mode_dot_field/norm
|
|
69
69
|
return svec
|
|
70
70
|
|
|
71
71
|
def sparam_mode_power(nodes: np.ndarray,
|
|
72
72
|
tri_vertices: np.ndarray,
|
|
73
|
-
bc:
|
|
73
|
+
bc: PortBC,
|
|
74
74
|
k0: float,
|
|
75
75
|
const: np.ndarray,
|
|
76
|
-
|
|
76
|
+
gq_order: int = 4):
|
|
77
77
|
''' Compute the S-parameters assuming a wave port mode
|
|
78
78
|
|
|
79
79
|
Arguments:
|
|
@@ -83,7 +83,7 @@ def sparam_mode_power(nodes: np.ndarray,
|
|
|
83
83
|
bc: RobinBC = The port boundary condition object
|
|
84
84
|
freq: float = The frequency at which to do the calculation
|
|
85
85
|
fielf: Callable = The interpolation fuction that computes the E-field from the simulation
|
|
86
|
-
|
|
86
|
+
gq_order: int = 4 the Gauss-Quadrature order (default = 4)
|
|
87
87
|
'''
|
|
88
88
|
|
|
89
89
|
def modef(x, y, z):
|
|
@@ -94,17 +94,17 @@ def sparam_mode_power(nodes: np.ndarray,
|
|
|
94
94
|
Ex2, Ey2, Ez2 = np.conj(modef(x,y,z))
|
|
95
95
|
return (Ex1*Ex2 + Ey1*Ey2 + Ez1*Ez2)/(2*bc.Zmode(k0))
|
|
96
96
|
|
|
97
|
-
norm = surface_integral(nodes, tri_vertices, inproduct2, const, gq_order=
|
|
97
|
+
norm = surface_integral(nodes, tri_vertices, inproduct2, const, gq_order=gq_order)
|
|
98
98
|
|
|
99
99
|
return norm
|
|
100
100
|
|
|
101
101
|
def sparam_field_power(nodes: np.ndarray,
|
|
102
102
|
tri_vertices: np.ndarray,
|
|
103
|
-
bc:
|
|
103
|
+
bc: PortBC,
|
|
104
104
|
k0: float,
|
|
105
105
|
fieldf: Callable,
|
|
106
106
|
const: np.ndarray,
|
|
107
|
-
|
|
107
|
+
gq_order: int = 4) -> complex:
|
|
108
108
|
''' Compute the S-parameters assuming a wave port mode
|
|
109
109
|
|
|
110
110
|
Arguments:
|
|
@@ -114,7 +114,7 @@ def sparam_field_power(nodes: np.ndarray,
|
|
|
114
114
|
bc: RobinBC = The port boundary condition object
|
|
115
115
|
freq: float = The frequency at which to do the calculation
|
|
116
116
|
fielf: Callable = The interpolation fuction that computes the E-field from the simulation
|
|
117
|
-
|
|
117
|
+
gq_order: int = 4 the Gauss-Quadrature order (default = 4)
|
|
118
118
|
'''
|
|
119
119
|
|
|
120
120
|
def modef(x, y, z):
|
|
@@ -132,7 +132,7 @@ def sparam_field_power(nodes: np.ndarray,
|
|
|
132
132
|
Ex2, Ey2, Ez2 = np.conj(modef(x,y,z))
|
|
133
133
|
return (Ex1*Ex2 + Ey1*Ey2 + Ez1*Ez2) / (2*bc.Zmode(k0))
|
|
134
134
|
|
|
135
|
-
mode_dot_field = surface_integral(nodes, tri_vertices, inproduct1, const, gq_order=
|
|
135
|
+
mode_dot_field = surface_integral(nodes, tri_vertices, inproduct1, const, gq_order=gq_order)
|
|
136
136
|
|
|
137
137
|
svec = mode_dot_field
|
|
138
138
|
return svec
|
|
@@ -31,7 +31,7 @@ def generate_touchstone(filename: str,
|
|
|
31
31
|
freq: np.ndarray,
|
|
32
32
|
Smat: np.ndarray,
|
|
33
33
|
data_format: Literal['RI','MA','DB'],
|
|
34
|
-
custom_comments: list[str] = None,
|
|
34
|
+
custom_comments: list[str] | None = None,
|
|
35
35
|
funit: Literal['HZ','KHZ','MHZ','GHZ'] = 'GHZ') -> None:
|
|
36
36
|
"""
|
|
37
37
|
Export S-parameter data to a Touchstone file
|
emerge/_emerge/plot/display.py
CHANGED
|
@@ -18,7 +18,7 @@ class BaseDisplay:
|
|
|
18
18
|
def show(self):
|
|
19
19
|
raise NotImplementedError('This method is not implemented')
|
|
20
20
|
|
|
21
|
-
def add_object(self, obj: GeoObject | Selection
|
|
21
|
+
def add_object(self, obj: GeoObject | Selection,*args, **kwargs):
|
|
22
22
|
""" Adds an object to the display
|
|
23
23
|
|
|
24
24
|
Keyword arguments
|
|
@@ -352,14 +352,20 @@ class BaseDisplay:
|
|
|
352
352
|
def add_scatter(self, xs: np.ndarray, ys: np.ndarray, zs: np.ndarray):
|
|
353
353
|
raise NotImplementedError('This method is not implemented')
|
|
354
354
|
|
|
355
|
-
def add_portmode(self, port: PortBC,
|
|
356
|
-
|
|
355
|
+
def add_portmode(self, port: PortBC,
|
|
356
|
+
Npoints: int = 10,
|
|
357
|
+
dv=(0,0,0),
|
|
358
|
+
XYZ=None,
|
|
359
|
+
field: Literal['E','H'] = 'E',
|
|
360
|
+
k0: float | None = None,
|
|
361
|
+
mode_number: int | None = None):
|
|
357
362
|
raise NotImplementedError('This method is not implemented')
|
|
358
363
|
|
|
359
364
|
def add_quiver(self, x: np.ndarray, y: np.ndarray, z: np.ndarray,
|
|
360
365
|
dx: np.ndarray, dy: np.ndarray, dz: np.ndarray,
|
|
361
366
|
scale: float = 1,
|
|
362
|
-
|
|
367
|
+
color: tuple[float, float, float] | None = None,
|
|
368
|
+
scalemode: Literal['lin','log'] = 'lin') -> None:
|
|
363
369
|
|
|
364
370
|
raise NotImplementedError('This method is not implemented')
|
|
365
371
|
|
|
@@ -370,10 +376,10 @@ class BaseDisplay:
|
|
|
370
376
|
field: np.ndarray,
|
|
371
377
|
scale: Literal['lin','log','symlog'] = 'lin',
|
|
372
378
|
cmap: cmap_names = 'coolwarm',
|
|
373
|
-
clim: tuple[float, float] = None,
|
|
379
|
+
clim: tuple[float, float] | None = None,
|
|
374
380
|
opacity: float = 1.0,
|
|
375
381
|
symmetrize: bool = True,
|
|
376
|
-
|
|
382
|
+
_fieldname: str | None = None,
|
|
377
383
|
**kwargs,):
|
|
378
384
|
"""Add a surface plot to the display
|
|
379
385
|
The X,Y,Z coordinates must be a 2D grid of data points. The field must be a real field with the same size.
|