emerge 1.0.1__py3-none-any.whl → 1.0.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/__init__.py +6 -7
- emerge/_emerge/elements/femdata.py +4 -3
- emerge/_emerge/elements/nedelec2.py +8 -4
- emerge/_emerge/elements/nedleg2.py +6 -2
- emerge/_emerge/geo/pcb.py +6 -2
- emerge/_emerge/geo/pcb_tools/dxf.py +4 -3
- emerge/_emerge/geo/polybased.py +2 -59
- emerge/_emerge/mesh3d.py +23 -31
- emerge/_emerge/{_cache_check.py → mth/_cache_check.py} +2 -2
- emerge/_emerge/mth/optimized.py +69 -3
- emerge/_emerge/physics/microwave/__init__.py +0 -1
- emerge/_emerge/physics/microwave/assembly/assembler.py +27 -5
- emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +2 -3
- emerge/_emerge/physics/microwave/assembly/periodicbc.py +0 -1
- emerge/_emerge/physics/microwave/assembly/robin_abc_order2.py +375 -0
- emerge/_emerge/physics/microwave/assembly/robinbc.py +37 -38
- emerge/_emerge/physics/microwave/microwave_3d.py +11 -19
- emerge/_emerge/physics/microwave/microwave_bc.py +30 -17
- emerge/_emerge/physics/microwave/microwave_data.py +0 -26
- emerge/_emerge/physics/microwave/port_functions.py +4 -4
- emerge/_emerge/plot/pyvista/display.py +14 -4
- emerge/_emerge/selection.py +2 -1
- emerge/_emerge/simmodel.py +1 -1
- emerge/_emerge/solver.py +1 -0
- emerge/lib.py +0 -2
- {emerge-1.0.1.dist-info → emerge-1.0.3.dist-info}/METADATA +16 -4
- {emerge-1.0.1.dist-info → emerge-1.0.3.dist-info}/RECORD +30 -29
- {emerge-1.0.1.dist-info → emerge-1.0.3.dist-info}/WHEEL +0 -0
- {emerge-1.0.1.dist-info → emerge-1.0.3.dist-info}/entry_points.txt +0 -0
- {emerge-1.0.1.dist-info → emerge-1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# EMerge is an open source Python based FEM EM simulation module.
|
|
2
|
+
# Copyright (C) 2025 Robert Fennis.
|
|
3
|
+
|
|
4
|
+
# This program is free software; you can redistribute it and/or
|
|
5
|
+
# modify it under the terms of the GNU General Public License
|
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
|
7
|
+
# of the License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see
|
|
16
|
+
# <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
from ....elements import Nedelec2
|
|
21
|
+
from scipy.sparse import csr_matrix
|
|
22
|
+
from ....mth.optimized import local_mapping, compute_distances
|
|
23
|
+
from numba import c16, types, f8, i8, njit, prange
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
############################################################
|
|
27
|
+
# FIELD MAPPING #
|
|
28
|
+
############################################################
|
|
29
|
+
|
|
30
|
+
@njit(i8[:,:](i8, i8[:,:], i8[:,:], i8[:,:]), cache=True, nogil=True)
|
|
31
|
+
def local_tri_to_edgeid(itri: int, tris, edges, tri_to_edge) -> np.ndarray:
|
|
32
|
+
global_edge_map = edges[:, tri_to_edge[:,itri]]
|
|
33
|
+
return local_mapping(tris[:, itri], global_edge_map)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@njit(cache=True, fastmath=True, nogil=True)
|
|
37
|
+
def optim_matmul(B: np.ndarray, data: np.ndarray):
|
|
38
|
+
dnew = np.zeros_like(data)
|
|
39
|
+
dnew[0,:] = B[0,0]*data[0,:] + B[0,1]*data[1,:] + B[0,2]*data[2,:]
|
|
40
|
+
dnew[1,:] = B[1,0]*data[0,:] + B[1,1]*data[1,:] + B[1,2]*data[2,:]
|
|
41
|
+
dnew[2,:] = B[2,0]*data[0,:] + B[2,1]*data[1,:] + B[2,2]*data[2,:]
|
|
42
|
+
return dnew
|
|
43
|
+
|
|
44
|
+
@njit(f8[:](f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
|
|
45
|
+
def cross(a: np.ndarray, b: np.ndarray):
|
|
46
|
+
crossv = np.empty((3,), dtype=np.float64)
|
|
47
|
+
crossv[0] = a[1]*b[2] - a[2]*b[1]
|
|
48
|
+
crossv[1] = a[2]*b[0] - a[0]*b[2]
|
|
49
|
+
crossv[2] = a[0]*b[1] - a[1]*b[0]
|
|
50
|
+
return crossv
|
|
51
|
+
|
|
52
|
+
@njit(cache=True, nogil=True)
|
|
53
|
+
def normalize(a: np.ndarray):
|
|
54
|
+
return a/((a[0]**2 + a[1]**2 + a[2]**2)**0.5)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
############################################################
|
|
58
|
+
# GAUSS QUADRATURE IMPLEMENTATION #
|
|
59
|
+
############################################################
|
|
60
|
+
|
|
61
|
+
@njit(c16(c16[:], c16[:], types.Array(types.float64, 1, 'A', readonly=True)), cache=True, nogil=True)
|
|
62
|
+
def _gqi(v1, v2, W):
|
|
63
|
+
return np.sum(v1*v2*W)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
############################################################
|
|
67
|
+
# BASIS FUNCTION DERIVATIVES #
|
|
68
|
+
############################################################
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
72
|
+
def _curl_edge_1(coeff, coords):
|
|
73
|
+
a1, b1, c1 = coeff[:,0]
|
|
74
|
+
a2, b2, c2 = coeff[:,1]
|
|
75
|
+
xs = coords[0,:]
|
|
76
|
+
ys = coords[1,:]
|
|
77
|
+
out = -3*a1*b1*c2 + 3*a1*b2*c1 - 3*b1**2*c2*xs + 3*b1*b2*c1*xs - 3*b1*c1*c2*ys + 3*b2*c1**2*ys + 0j
|
|
78
|
+
return out
|
|
79
|
+
|
|
80
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
81
|
+
def _curl_edge_2(coeff, coords):
|
|
82
|
+
a1, b1, c1 = coeff[:,0]
|
|
83
|
+
a2, b2, c2 = coeff[:,1]
|
|
84
|
+
xs = coords[0,:]
|
|
85
|
+
ys = coords[1,:]
|
|
86
|
+
out = -3*a2*b1*c2 + 3*a2*b2*c1 - 3*b1*b2*c2*xs - 3*b1*c2**2*ys + 3*b2**2*c1*xs + 3*b2*c1*c2*ys + 0j
|
|
87
|
+
return out
|
|
88
|
+
|
|
89
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
90
|
+
def _curl_face_1(coeff, coords):
|
|
91
|
+
a1, b1, c1 = coeff[:,0]
|
|
92
|
+
a2, b2, c2 = coeff[:,1]
|
|
93
|
+
a3, b3, c3 = coeff[:,2]
|
|
94
|
+
xs = coords[0,:]
|
|
95
|
+
ys = coords[1,:]
|
|
96
|
+
out = -b2*(c1*(a3 + b3*xs + c3*ys) - c3*(a1 + b1*xs + c1*ys)) + c2*(b1*(a3 + b3*xs + c3*ys) - b3*(a1 + b1*xs + c1*ys)) + 2*(b1*c3 - b3*c1)*(a2 + b2*xs + c2*ys) + 0j
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
100
|
+
def _curl_face_2(coeff, coords):
|
|
101
|
+
a1, b1, c1 = coeff[:,0]
|
|
102
|
+
a2, b2, c2 = coeff[:,1]
|
|
103
|
+
a3, b3, c3 = coeff[:,2]
|
|
104
|
+
xs = coords[0,:]
|
|
105
|
+
ys = coords[1,:]
|
|
106
|
+
out = b3*(c1*(a2 + b2*xs + c2*ys) - c2*(a1 + b1*xs + c1*ys)) - c3*(b1*(a2 + b2*xs + c2*ys) - b2*(a1 + b1*xs + c1*ys)) - 2*(b1*c2 - b2*c1)*(a3 + b3*xs + c3*ys) + 0j
|
|
107
|
+
return out
|
|
108
|
+
|
|
109
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
110
|
+
def _divergence_edge_1(coeff, coords):
|
|
111
|
+
a1, b1, c1 = coeff[:,0]
|
|
112
|
+
a2, b2, c2 = coeff[:,1]
|
|
113
|
+
xs = coords[0,:]
|
|
114
|
+
ys = coords[1,:]
|
|
115
|
+
out = b1*(b1*(a2 + b2*xs + c2*ys) - b2*(a1 + b1*xs + c1*ys)) + c1*(c1*(a2 + b2*xs + c2*ys) - c2*(a1 + b1*xs + c1*ys)) + 0j
|
|
116
|
+
return out
|
|
117
|
+
|
|
118
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
119
|
+
def _divergence_edge_2(coeff, coords):
|
|
120
|
+
a1, b1, c1 = coeff[:,0]
|
|
121
|
+
a2, b2, c2 = coeff[:,1]
|
|
122
|
+
xs = coords[0,:]
|
|
123
|
+
ys = coords[1,:]
|
|
124
|
+
out = b2*(b1*(a2 + b2*xs + c2*ys) - b2*(a1 + b1*xs + c1*ys)) + c2*(c1*(a2 + b2*xs + c2*ys) - c2*(a1 + b1*xs + c1*ys)) + 0j
|
|
125
|
+
return out
|
|
126
|
+
|
|
127
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
128
|
+
def _divergence_face_1(coeff, coords):
|
|
129
|
+
a1, b1, c1 = coeff[:,0]
|
|
130
|
+
a2, b2, c2 = coeff[:,1]
|
|
131
|
+
a3, b3, c3 = coeff[:,2]
|
|
132
|
+
xs = coords[0,:]
|
|
133
|
+
ys = coords[1,:]
|
|
134
|
+
out = -b2*(b1*(a3 + b3*xs + c3*ys) - b3*(a1 + b1*xs + c1*ys)) - c2*(c1*(a3 + b3*xs + c3*ys) - c3*(a1 + b1*xs + c1*ys)) + 0j
|
|
135
|
+
return out
|
|
136
|
+
|
|
137
|
+
@njit(c16[:](f8[:,:], f8[:,:]), cache=True)
|
|
138
|
+
def _divergence_face_2(coeff, coords):
|
|
139
|
+
a1, b1, c1 = coeff[:,0]
|
|
140
|
+
a2, b2, c2 = coeff[:,1]
|
|
141
|
+
a3, b3, c3 = coeff[:,2]
|
|
142
|
+
xs = coords[0,:]
|
|
143
|
+
ys = coords[1,:]
|
|
144
|
+
out = b3*(b1*(a2 + b2*xs + c2*ys) - b2*(a1 + b1*xs + c1*ys)) + c3*(c1*(a2 + b2*xs + c2*ys) - c2*(a1 + b1*xs + c1*ys)) + 0j
|
|
145
|
+
return out
|
|
146
|
+
|
|
147
|
+
############################################################
|
|
148
|
+
# TRIANGLE BARYCENTRIC COORDINATE LIN. COEFFICIENTS #
|
|
149
|
+
############################################################
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@njit(types.Tuple((f8[:], f8[:], f8[:], f8))(f8[:], f8[:]), cache = True, nogil=True)
|
|
153
|
+
def tri_coefficients(vxs, vys):
|
|
154
|
+
|
|
155
|
+
x1, x2, x3 = vxs
|
|
156
|
+
y1, y2, y3 = vys
|
|
157
|
+
|
|
158
|
+
a1 = x2*y3-y2*x3
|
|
159
|
+
a2 = x3*y1-y3*x1
|
|
160
|
+
a3 = x1*y2-y1*x2
|
|
161
|
+
b1 = y2-y3
|
|
162
|
+
b2 = y3-y1
|
|
163
|
+
b3 = y1-y2
|
|
164
|
+
c1 = x3-x2
|
|
165
|
+
c2 = x1-x3
|
|
166
|
+
c3 = x2-x1
|
|
167
|
+
|
|
168
|
+
sA = 0.5*(((x1-x3)*(y2-y1) - (x1-x2)*(y3-y1)))
|
|
169
|
+
sign = np.sign(sA)
|
|
170
|
+
A = np.abs(sA)
|
|
171
|
+
As = np.array([a1, a2, a3])*sign
|
|
172
|
+
Bs = np.array([b1, b2, b3])*sign
|
|
173
|
+
Cs = np.array([c1, c2, c3])*sign
|
|
174
|
+
return As, Bs, Cs, A
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
############################################################
|
|
178
|
+
# GAUSS QUADRATURE POINTS #
|
|
179
|
+
############################################################
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
DPTS = np.array([[0.22338159, 0.22338159, 0.22338159, 0.10995174, 0.10995174, 0.10995174],
|
|
183
|
+
[0.10810302, 0.44594849, 0.44594849, 0.81684757, 0.09157621, 0.09157621],
|
|
184
|
+
[0.44594849, 0.44594849, 0.10810302, 0.09157621, 0.09157621, 0.81684757],
|
|
185
|
+
[0.44594849, 0.10810302, 0.44594849, 0.09157621, 0.81684757, 0.09157621]], dtype=np.float64)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
############################################################
|
|
189
|
+
# NUMBA OPTIMIZED ASSEMBLER #
|
|
190
|
+
############################################################
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@njit(c16[:,:](f8[:,:], i8[:,:], c16), cache=True, nogil=True)
|
|
194
|
+
def _abc_order_2_terms(tri_vertices, local_edge_map, cf):
|
|
195
|
+
'''ABC order 2 tangent gradient term'''
|
|
196
|
+
|
|
197
|
+
origin = tri_vertices[:,0]
|
|
198
|
+
vertex_2 = tri_vertices[:,1]
|
|
199
|
+
vertex_3 = tri_vertices[:,2]
|
|
200
|
+
|
|
201
|
+
edge_1 = vertex_2-origin
|
|
202
|
+
edge_2 = vertex_3-origin
|
|
203
|
+
|
|
204
|
+
zhat = normalize(cross(edge_1, edge_2))
|
|
205
|
+
xhat = normalize(edge_1)
|
|
206
|
+
yhat = normalize(cross(zhat, xhat))
|
|
207
|
+
|
|
208
|
+
basis = np.zeros((3,3), dtype=np.float64)
|
|
209
|
+
basis[0,:] = xhat
|
|
210
|
+
basis[1,:] = yhat
|
|
211
|
+
basis[2,:] = zhat
|
|
212
|
+
|
|
213
|
+
local_vertices = optim_matmul(basis, tri_vertices - origin[:,np.newaxis])
|
|
214
|
+
|
|
215
|
+
CurlMatrix = np.zeros((8,8), dtype=np.complex128)
|
|
216
|
+
DivMatrix = np.zeros((8,8), dtype=np.complex128)
|
|
217
|
+
|
|
218
|
+
Lengths = np.ones((8,8), dtype=np.float64)
|
|
219
|
+
|
|
220
|
+
WEIGHTS = DPTS[0,:]
|
|
221
|
+
DPTS1 = DPTS[1,:]
|
|
222
|
+
DPTS2 = DPTS[2,:]
|
|
223
|
+
DPTS3 = DPTS[3,:]
|
|
224
|
+
|
|
225
|
+
xpts = local_vertices[0,:]
|
|
226
|
+
ypts = local_vertices[1,:]
|
|
227
|
+
|
|
228
|
+
distances = compute_distances(xpts, ypts, 0*xpts)
|
|
229
|
+
|
|
230
|
+
xs = xpts[0]*DPTS1 + xpts[1]*DPTS2 + xpts[2]*DPTS3
|
|
231
|
+
ys = ypts[0]*DPTS1 + ypts[1]*DPTS2 + ypts[2]*DPTS3
|
|
232
|
+
|
|
233
|
+
int_coords = np.empty((2,xs.shape[0]), dtype=np.float64)
|
|
234
|
+
int_coords[0,:] = xs
|
|
235
|
+
int_coords[1,:] = ys
|
|
236
|
+
|
|
237
|
+
aas, bbs, ccs, Area = tri_coefficients(xpts, ypts)
|
|
238
|
+
|
|
239
|
+
bary_coeff = np.empty((3,3), dtype=np.float64)
|
|
240
|
+
bary_coeff[0,:] = aas/(2*Area)
|
|
241
|
+
bary_coeff[1,:] = bbs/(2*Area)
|
|
242
|
+
bary_coeff[2,:] = ccs/(2*Area)
|
|
243
|
+
|
|
244
|
+
Lengths[3,:] *= distances[0,2]
|
|
245
|
+
Lengths[7,:] *= distances[0,1]
|
|
246
|
+
Lengths[:,3] *= distances[0,2]
|
|
247
|
+
Lengths[:,7] *= distances[0,1]
|
|
248
|
+
|
|
249
|
+
FF1C = _curl_face_1(bary_coeff, int_coords)
|
|
250
|
+
FF2C = _curl_face_2(bary_coeff, int_coords)
|
|
251
|
+
FF1D = _divergence_face_1(bary_coeff, int_coords)
|
|
252
|
+
FF2D = _divergence_face_2(bary_coeff, int_coords)
|
|
253
|
+
|
|
254
|
+
for iv1 in range(3):
|
|
255
|
+
ie1 = local_edge_map[:, iv1]
|
|
256
|
+
|
|
257
|
+
Le = distances[ie1[0], ie1[1]]
|
|
258
|
+
Lengths[iv1,:] *= Le
|
|
259
|
+
Lengths[iv1+4,:] *= Le
|
|
260
|
+
Lengths[:,iv1] *= Le
|
|
261
|
+
Lengths[:,iv1+4] *= Le
|
|
262
|
+
|
|
263
|
+
FE1C_1 = _curl_edge_1(bary_coeff[:,ie1], int_coords)
|
|
264
|
+
FE2C_1 = _curl_edge_2(bary_coeff[:,ie1], int_coords)
|
|
265
|
+
FE1D_1 = _divergence_edge_1(bary_coeff[:,ie1], int_coords)
|
|
266
|
+
FE2D_1 = _divergence_edge_2(bary_coeff[:,ie1], int_coords)
|
|
267
|
+
|
|
268
|
+
for iv2 in range(3):
|
|
269
|
+
ie2 = local_edge_map[:, iv2]
|
|
270
|
+
|
|
271
|
+
FE1C_2 = _curl_edge_1(bary_coeff[:,ie2], int_coords)
|
|
272
|
+
FE2C_2 = _curl_edge_2(bary_coeff[:,ie2], int_coords)
|
|
273
|
+
FE1D_2 = _divergence_edge_1(bary_coeff[:,ie2], int_coords)
|
|
274
|
+
FE2D_2 = _divergence_edge_2(bary_coeff[:,ie2], int_coords)
|
|
275
|
+
|
|
276
|
+
CurlMatrix[iv1, iv2] = _gqi(FE1C_1, FE1C_2, WEIGHTS)
|
|
277
|
+
CurlMatrix[iv1, iv2+4] = _gqi(FE1C_1, FE2C_2, WEIGHTS)
|
|
278
|
+
CurlMatrix[iv1+4, iv2] = _gqi(FE2C_1, FE1C_2, WEIGHTS)
|
|
279
|
+
CurlMatrix[iv1+4, iv2+4] = _gqi(FE2C_1, FE2C_2, WEIGHTS)
|
|
280
|
+
|
|
281
|
+
DivMatrix[iv1, iv2] = _gqi(FE1D_1, FE1D_2, WEIGHTS)
|
|
282
|
+
DivMatrix[iv1, iv2+4] = _gqi(FE1D_1, FE2D_2, WEIGHTS)
|
|
283
|
+
DivMatrix[iv1+4, iv2] = _gqi(FE2D_1, FE1D_2, WEIGHTS)
|
|
284
|
+
DivMatrix[iv1+4, iv2+4] = _gqi(FE2D_1, FE2D_2, WEIGHTS)
|
|
285
|
+
|
|
286
|
+
CurlMatrix[iv1, 3] = _gqi(FE1C_1, FF1C, WEIGHTS)
|
|
287
|
+
CurlMatrix[iv1+4,3] = _gqi(FE2C_1, FF1C, WEIGHTS)
|
|
288
|
+
CurlMatrix[iv1, 7] = _gqi(FE1C_1, FF2C, WEIGHTS)
|
|
289
|
+
CurlMatrix[iv1+4,7] = _gqi(FE2C_1, FF2C, WEIGHTS)
|
|
290
|
+
|
|
291
|
+
CurlMatrix[3, iv1] = CurlMatrix[iv1, 3]
|
|
292
|
+
CurlMatrix[3, iv1+4] = CurlMatrix[iv1+4, 3]
|
|
293
|
+
CurlMatrix[7, iv1] = CurlMatrix[iv1, 7]
|
|
294
|
+
CurlMatrix[7, iv1+4] = CurlMatrix[iv1+4, 7]
|
|
295
|
+
|
|
296
|
+
DivMatrix[iv1, 3] = _gqi(FE1D_1, FF1D, WEIGHTS)
|
|
297
|
+
DivMatrix[iv1+4,3] = _gqi(FE2D_1, FF1D, WEIGHTS)
|
|
298
|
+
DivMatrix[iv1, 7] = _gqi(FE1D_1, FF2D, WEIGHTS)
|
|
299
|
+
DivMatrix[iv1+4,7] = _gqi(FE2D_1, FF2D, WEIGHTS)
|
|
300
|
+
|
|
301
|
+
DivMatrix[3, iv1] = DivMatrix[iv1, 3]
|
|
302
|
+
DivMatrix[3, iv1+4] = DivMatrix[iv1+4, 3]
|
|
303
|
+
DivMatrix[7, iv1] = DivMatrix[iv1, 7]
|
|
304
|
+
DivMatrix[7, iv1+4] = DivMatrix[iv1+4, 7]
|
|
305
|
+
|
|
306
|
+
CurlMatrix[3, 3] = _gqi(FF1C, FF1C, WEIGHTS)
|
|
307
|
+
CurlMatrix[3, 7] = _gqi(FF1C, FF2C, WEIGHTS)
|
|
308
|
+
CurlMatrix[7, 3] = _gqi(FF2C, FF1C, WEIGHTS)
|
|
309
|
+
CurlMatrix[7, 7] = _gqi(FF2C, FF2C, WEIGHTS)
|
|
310
|
+
|
|
311
|
+
DivMatrix[3, 3] = _gqi(FF1D, FF1D, WEIGHTS)
|
|
312
|
+
DivMatrix[3, 7] = _gqi(FF1D, FF2D, WEIGHTS)
|
|
313
|
+
DivMatrix[7, 3] = _gqi(FF2D, FF1D, WEIGHTS)
|
|
314
|
+
DivMatrix[7, 7] = _gqi(FF2D, FF2D, WEIGHTS)
|
|
315
|
+
|
|
316
|
+
Mat = cf*Lengths*(CurlMatrix-DivMatrix)*np.abs(Area)
|
|
317
|
+
return Mat
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
############################################################
|
|
321
|
+
# NUMBA OPTIMIZED INTEGRAL OVER TETS #
|
|
322
|
+
############################################################
|
|
323
|
+
|
|
324
|
+
@njit((c16[:])(f8[:,:],
|
|
325
|
+
i8[:,:],
|
|
326
|
+
i8[:,:],
|
|
327
|
+
i8[:,:],
|
|
328
|
+
i8[:],
|
|
329
|
+
c16), cache=True, nogil=True, parallel=True)
|
|
330
|
+
def _matrix_builder(nodes, tris, edges, tri_to_field, tri_ids, coeff):
|
|
331
|
+
""" Numba optimized loop over each face triangle."""
|
|
332
|
+
ntritot = tris.shape[1]
|
|
333
|
+
nnz = ntritot*64
|
|
334
|
+
|
|
335
|
+
Mat = np.zeros(nnz, dtype=np.complex128)
|
|
336
|
+
|
|
337
|
+
tri_to_edge = tri_to_field[:3,:]
|
|
338
|
+
|
|
339
|
+
Ntris = tri_ids.shape[0]
|
|
340
|
+
for itri_sub in prange(Ntris): # type: ignore
|
|
341
|
+
|
|
342
|
+
itri = tri_ids[itri_sub]
|
|
343
|
+
p = itri*64
|
|
344
|
+
|
|
345
|
+
# Construct a local mapping to global triangle orientations
|
|
346
|
+
local_tri_map = local_tri_to_edgeid(itri, tris, edges, tri_to_edge)
|
|
347
|
+
|
|
348
|
+
# Construct the local edge map
|
|
349
|
+
tri_nodes = nodes[:, tris[:,itri]]
|
|
350
|
+
subMat = _abc_order_2_terms(tri_nodes, local_tri_map, coeff)
|
|
351
|
+
|
|
352
|
+
Mat[p:p+64] += subMat.ravel()
|
|
353
|
+
|
|
354
|
+
return Mat
|
|
355
|
+
|
|
356
|
+
############################################################
|
|
357
|
+
# PYTHON INTERFACE #
|
|
358
|
+
############################################################
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def abc_order_2_matrix(field: Nedelec2,
|
|
362
|
+
surf_triangle_indices: np.ndarray,
|
|
363
|
+
coeff: complex) -> np.ndarray:
|
|
364
|
+
"""Computes the second order absorbing boundary condition correction terms.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
field (Nedelec2): The Basis function object
|
|
368
|
+
surf_triangle_indices (np.ndarray): The surface triangle indices to add
|
|
369
|
+
coeff (complex): The integral coefficient jp2/k0
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
np.ndarray: The resultant matrix items
|
|
373
|
+
"""
|
|
374
|
+
Mat = _matrix_builder(field.mesh.nodes, field.mesh.tris, field.mesh.edges, field.tri_to_field, surf_triangle_indices, coeff)
|
|
375
|
+
return Mat
|
|
@@ -312,34 +312,31 @@ def compute_bc_entries_excited(vertices_global, tris, Bmat, Bvec, surf_triangle_
|
|
|
312
312
|
|
|
313
313
|
|
|
314
314
|
@njit(c16[:,:](f8[:,:], f8[:], c16), cache=True, nogil=True, parallel=False)
|
|
315
|
-
def ned2_tri_stiff(
|
|
315
|
+
def ned2_tri_stiff(glob_vertices, edge_lengths, gamma):
|
|
316
316
|
''' Nedelec-2 Triangle Stiffness matrix and forcing vector (For Boundary Condition of the Third Kind)
|
|
317
317
|
|
|
318
318
|
'''
|
|
319
319
|
local_edge_map = np.array([[0,1,0],[1,2,2]])
|
|
320
320
|
Bmat = np.zeros((8,8), dtype=np.complex128)
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
axn = cross(ax1, ax2)
|
|
332
|
-
ax2 = -cross(axn, ax1)
|
|
322
|
+
orig = glob_vertices[:,0]
|
|
323
|
+
v2 = glob_vertices[:,1]
|
|
324
|
+
v3 = glob_vertices[:,2]
|
|
325
|
+
|
|
326
|
+
e1 = v2-orig
|
|
327
|
+
e2 = v3-orig
|
|
328
|
+
zhat = normalize(cross(e1, e2))
|
|
329
|
+
xhat = normalize(e1)
|
|
330
|
+
yhat = normalize(cross(zhat, xhat))
|
|
333
331
|
basis = np.zeros((3,3), dtype=np.float64)
|
|
334
|
-
basis[
|
|
335
|
-
basis[
|
|
336
|
-
basis[
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
332
|
+
basis[0,:] = xhat
|
|
333
|
+
basis[1,:] = yhat
|
|
334
|
+
basis[2,:] = zhat
|
|
335
|
+
lcs_vertices = optim_matmul(basis, glob_vertices - orig[:,np.newaxis])
|
|
336
|
+
|
|
340
337
|
xs = lcs_vertices[0,:]
|
|
341
338
|
ys = lcs_vertices[1,:]
|
|
342
|
-
|
|
339
|
+
|
|
343
340
|
x1, x2, x3 = xs
|
|
344
341
|
y1, y2, y3 = ys
|
|
345
342
|
|
|
@@ -359,7 +356,7 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
359
356
|
GLs = (GL1, GL2, GL3)
|
|
360
357
|
|
|
361
358
|
Area = 0.5 * np.abs((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1))
|
|
362
|
-
|
|
359
|
+
|
|
363
360
|
letters = [1,2,3,4,5,6]
|
|
364
361
|
|
|
365
362
|
tA, tB, tC = letters[0], letters[1], letters[2]
|
|
@@ -367,11 +364,12 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
367
364
|
|
|
368
365
|
Lt1, Lt2 = Ds[2, 0], Ds[1, 0]
|
|
369
366
|
|
|
367
|
+
|
|
370
368
|
COEFF = gamma/(2*Area)**2
|
|
371
369
|
AREA_COEFF = AREA_COEFF_CACHE_BASE * Area
|
|
372
370
|
for ei in range(3):
|
|
373
371
|
ei1, ei2 = local_edge_map[:, ei]
|
|
374
|
-
Li =
|
|
372
|
+
Li = Ds[ei1, ei2]
|
|
375
373
|
|
|
376
374
|
A = letters[ei1]
|
|
377
375
|
B = letters[ei2]
|
|
@@ -381,24 +379,25 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
381
379
|
|
|
382
380
|
for ej in range(3):
|
|
383
381
|
ej1, ej2 = local_edge_map[:, ej]
|
|
384
|
-
Lj =
|
|
382
|
+
Lj = Ds[ej1, ej2]
|
|
385
383
|
|
|
386
384
|
C = letters[ej1]
|
|
387
385
|
D = letters[ej2]
|
|
388
386
|
|
|
389
387
|
GC = GLs[ej1]
|
|
390
388
|
GD = GLs[ej2]
|
|
389
|
+
|
|
391
390
|
DAC = dot(GA,GC)
|
|
392
391
|
DAD = dot(GA,GD)
|
|
393
392
|
DBC = dot(GB,GC)
|
|
394
393
|
DBD = dot(GB,GD)
|
|
395
394
|
LL = Li*Lj
|
|
396
|
-
|
|
397
|
-
Bmat[ei,ej] += LL*
|
|
398
|
-
Bmat[ei,ej+4] += LL*
|
|
399
|
-
Bmat[ei+4,ej] += LL*
|
|
400
|
-
Bmat[ei+4,ej+4] += LL*
|
|
401
|
-
|
|
395
|
+
|
|
396
|
+
Bmat[ei,ej] += LL*(AREA_COEFF[A,B,C,D]*DAC-AREA_COEFF[A,B,C,C]*DAD-AREA_COEFF[A,A,C,D]*DBC+AREA_COEFF[A,A,C,C]*DBD)
|
|
397
|
+
Bmat[ei,ej+4] += LL*(AREA_COEFF[A,B,D,D]*DAC-AREA_COEFF[A,B,C,D]*DAD-AREA_COEFF[A,A,D,D]*DBC+AREA_COEFF[A,A,C,D]*DBD)
|
|
398
|
+
Bmat[ei+4,ej] += LL*(AREA_COEFF[B,B,C,D]*DAC-AREA_COEFF[B,B,C,C]*DAD-AREA_COEFF[A,B,C,D]*DBC+AREA_COEFF[A,B,C,C]*DBD)
|
|
399
|
+
Bmat[ei+4,ej+4] += LL*(AREA_COEFF[B,B,D,D]*DAC-AREA_COEFF[B,B,C,D]*DAD-AREA_COEFF[A,B,D,D]*DBC+AREA_COEFF[A,B,C,D]*DBD)
|
|
400
|
+
|
|
402
401
|
FA = dot(GA,GtC)
|
|
403
402
|
FB = dot(GA,GtA)
|
|
404
403
|
FC = dot(GB,GtC)
|
|
@@ -406,15 +405,15 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
406
405
|
FE = dot(GA,GtB)
|
|
407
406
|
FF = dot(GB,GtB)
|
|
408
407
|
|
|
409
|
-
Bmat[ei,3] += Li*Lt1*
|
|
410
|
-
Bmat[ei,7] += Li*Lt2*
|
|
411
|
-
Bmat[3,ei] += Lt1*Li*
|
|
412
|
-
Bmat[7,ei] += Lt2*Li*
|
|
413
|
-
Bmat[ei+4,3] += Li*Lt1*
|
|
414
|
-
Bmat[ei+4,7] += Li*Lt2*
|
|
415
|
-
Bmat[3,ei+4] += Lt1*Li*
|
|
416
|
-
Bmat[7,ei+4] += Lt2*Li*
|
|
417
|
-
|
|
408
|
+
Bmat[ei,3] += Li*Lt1*(AREA_COEFF[A,B,tA,tB]*FA-AREA_COEFF[A,B,tB,tC]*FB-AREA_COEFF[A,A,tA,tB]*FC+AREA_COEFF[A,A,tB,tC]*FD)
|
|
409
|
+
Bmat[ei,7] += Li*Lt2*(AREA_COEFF[A,B,tB,tC]*FB-AREA_COEFF[A,B,tC,tA]*FE-AREA_COEFF[A,A,tB,tC]*FD+AREA_COEFF[A,A,tC,tA]*FF)
|
|
410
|
+
Bmat[3,ei] += Lt1*Li*(AREA_COEFF[tA,tB,A,B]*FA-AREA_COEFF[tA,tB,A,A]*FC-AREA_COEFF[tB,tC,A,B]*FB+AREA_COEFF[tB,tC,A,A]*FD)
|
|
411
|
+
Bmat[7,ei] += Lt2*Li*(AREA_COEFF[tB,tC,A,B]*FB-AREA_COEFF[tB,tC,A,A]*FD-AREA_COEFF[tC,tA,A,B]*FE+AREA_COEFF[tC,tA,A,A]*FF)
|
|
412
|
+
Bmat[ei+4,3] += Li*Lt1*(AREA_COEFF[B,B,tA,tB]*FA-AREA_COEFF[B,B,tB,tC]*FB-AREA_COEFF[A,B,tA,tB]*FC+AREA_COEFF[A,B,tB,tC]*FD)
|
|
413
|
+
Bmat[ei+4,7] += Li*Lt2*(AREA_COEFF[B,B,tB,tC]*FB-AREA_COEFF[B,B,tC,tA]*FE-AREA_COEFF[A,B,tB,tC]*FD+AREA_COEFF[A,B,tC,tA]*FF)
|
|
414
|
+
Bmat[3,ei+4] += Lt1*Li*(AREA_COEFF[tA,tB,B,B]*FA-AREA_COEFF[tA,tB,A,B]*FC-AREA_COEFF[tB,tC,B,B]*FB+AREA_COEFF[tB,tC,A,B]*FD)
|
|
415
|
+
Bmat[7,ei+4] += Lt2*Li*(AREA_COEFF[tB,tC,B,B]*FB-AREA_COEFF[tB,tC,A,B]*FD-AREA_COEFF[tC,tA,B,B]*FE+AREA_COEFF[tC,tA,A,B]*FF)
|
|
416
|
+
|
|
418
417
|
H1 = dot(GtA,GtC)
|
|
419
418
|
H2 = dot(GtA,GtA)
|
|
420
419
|
H3 = dot(GtA,GtB)
|
|
@@ -423,8 +422,8 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
423
422
|
Bmat[3,7] += Lt1*Lt2*(AREA_COEFF[tA,tB,tB,tC]*H1-AREA_COEFF[tA,tB,tC,tA]*dot(GtB,GtC)-AREA_COEFF[tB,tC,tB,tC]*H2+AREA_COEFF[tB,tC,tC,tA]*H3)
|
|
424
423
|
Bmat[7,3] += Lt2*Lt1*(AREA_COEFF[tB,tC,tA,tB]*H1-AREA_COEFF[tB,tC,tB,tC]*H2-AREA_COEFF[tC,tA,tA,tB]*dot(GtB,GtC)+AREA_COEFF[tC,tA,tB,tC]*H3)
|
|
425
424
|
Bmat[7,7] += Lt2*Lt2*(AREA_COEFF[tB,tC,tB,tC]*H2-AREA_COEFF[tB,tC,tC,tA]*H3-AREA_COEFF[tC,tA,tB,tC]*H3+AREA_COEFF[tC,tA,tC,tA]*dot(GtB,GtB))
|
|
426
|
-
|
|
427
425
|
|
|
426
|
+
Bmat = Bmat * COEFF
|
|
428
427
|
return Bmat
|
|
429
428
|
|
|
430
429
|
@njit(c16[:](f8[:,:], i8[:,:], c16[:], f8[:,:], i8[:], c16), cache=True, nogil=True, parallel=False)
|
|
@@ -25,7 +25,6 @@ from ...elements.nedelec2 import Nedelec2
|
|
|
25
25
|
from ...solver import DEFAULT_ROUTINE, SolveRoutine
|
|
26
26
|
from ...system import called_from_main_function
|
|
27
27
|
from ...selection import FaceSelection
|
|
28
|
-
from ...mth.optimized import compute_distances
|
|
29
28
|
from ...settings import Settings
|
|
30
29
|
from .microwave_bc import MWBoundaryConditionSet, PEC, ModalPort, LumpedPort, PortBC
|
|
31
30
|
from .microwave_data import MWData
|
|
@@ -101,21 +100,6 @@ def shortest_path(xyz1: np.ndarray, xyz2: np.ndarray, Npts: int) -> np.ndarray:
|
|
|
101
100
|
path = (1 - t) * p1[:, np.newaxis] + t * p2[:, np.newaxis]
|
|
102
101
|
|
|
103
102
|
return path
|
|
104
|
-
|
|
105
|
-
def _pick_central(vertices: np.ndarray) -> np.ndarray:
|
|
106
|
-
"""Computes the coordinate in the vertex set that has the shortest square distance to all other points.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
vertices (np.ndarray): The set of coordinates [3,:]
|
|
111
|
-
|
|
112
|
-
Returns:
|
|
113
|
-
np.ndarray: The most central point
|
|
114
|
-
"""
|
|
115
|
-
Ds = compute_distances(vertices[0,:], vertices[1,:], vertices[2,:])
|
|
116
|
-
sumDs = np.sum(Ds**2, axis=1)
|
|
117
|
-
id_central = np.argwhere(sumDs==np.min(sumDs)).flatten()[0]
|
|
118
|
-
return vertices[:, id_central].squeeze()
|
|
119
103
|
|
|
120
104
|
class Microwave3D:
|
|
121
105
|
"""The Electrodynamics time harmonic physics class.
|
|
@@ -248,6 +232,14 @@ class Microwave3D:
|
|
|
248
232
|
self.set_frequency(np.linspace(fmin, fmax, Npoints))
|
|
249
233
|
|
|
250
234
|
def fdense(self, Npoints: int) -> np.ndarray:
|
|
235
|
+
"""Return a resampled version of the current frequency range
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
Npoints (int): The new number of points
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
np.ndarray: The new frequency axis
|
|
242
|
+
"""
|
|
251
243
|
if len(self.frequencies) == 1:
|
|
252
244
|
raise ValueError('Only 1 frequency point known. At least two need to be defined.')
|
|
253
245
|
fmin = min(self.frequencies)
|
|
@@ -497,7 +489,7 @@ class Microwave3D:
|
|
|
497
489
|
if freq is None:
|
|
498
490
|
freq = self.frequencies[0]
|
|
499
491
|
|
|
500
|
-
materials = self.mesh.
|
|
492
|
+
materials = self.mesh._get_material_assignment(self.mesher.volumes)
|
|
501
493
|
|
|
502
494
|
ertet = np.zeros((3,3,self.mesh.n_tets), dtype=np.complex128)
|
|
503
495
|
tandtet = np.zeros((3,3,self.mesh.n_tets), dtype=np.complex128)
|
|
@@ -655,7 +647,7 @@ class Microwave3D:
|
|
|
655
647
|
if self.basis is None:
|
|
656
648
|
raise SimulationError('Cannot proceed, the simulation basis class is undefined.')
|
|
657
649
|
|
|
658
|
-
materials = self.mesh.
|
|
650
|
+
materials = self.mesh._get_material_assignment(self.mesher.volumes)
|
|
659
651
|
|
|
660
652
|
### Does this move
|
|
661
653
|
logger.debug('Initializing frequency domain sweep.')
|
|
@@ -853,7 +845,7 @@ class Microwave3D:
|
|
|
853
845
|
if self.basis is None:
|
|
854
846
|
raise SimulationError('Cannot proceed. The simulation basis class is undefined.')
|
|
855
847
|
|
|
856
|
-
materials = self.mesh.
|
|
848
|
+
materials = self.mesh._get_material_assignment(self.mesher.volumes)
|
|
857
849
|
|
|
858
850
|
# er = self.mesh.retreive(lambda mat,x,y,z: mat.fer3d_mat(x,y,z), self.mesher.volumes)
|
|
859
851
|
# ur = self.mesh.retreive(lambda mat,x,y,z: mat.fur3d_mat(x,y,z), self.mesher.volumes)
|
|
@@ -19,19 +19,17 @@ from __future__ import annotations
|
|
|
19
19
|
import numpy as np
|
|
20
20
|
from loguru import logger
|
|
21
21
|
from typing import Callable, Literal
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from collections import defaultdict
|
|
22
24
|
from ...selection import Selection, FaceSelection
|
|
23
25
|
from ...cs import CoordinateSystem, Axis, GCS, _parse_axis
|
|
24
26
|
from ...coord import Line
|
|
25
27
|
from ...geometry import GeoSurface, GeoObject
|
|
26
|
-
from dataclasses import dataclass
|
|
27
|
-
from collections import defaultdict
|
|
28
28
|
from ...bc import BoundaryCondition, BoundaryConditionSet, Periodic
|
|
29
29
|
from ...periodic import PeriodicCell, HexCell, RectCell
|
|
30
30
|
from ...material import Material
|
|
31
31
|
from ...const import Z0, C0, EPS0, MU0
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
33
|
############################################################
|
|
36
34
|
# UTILITY FUNCTIONS #
|
|
37
35
|
############################################################
|
|
@@ -98,6 +96,15 @@ class MWBoundaryConditionSet(BoundaryConditionSet):
|
|
|
98
96
|
self._cell._ports.append(port)
|
|
99
97
|
return port
|
|
100
98
|
|
|
99
|
+
# Checks
|
|
100
|
+
def _is_excited(self) -> bool:
|
|
101
|
+
for bc in self.boundary_conditions:
|
|
102
|
+
if not isinstance(bc, RobinBC):
|
|
103
|
+
continue
|
|
104
|
+
if bc._include_force:
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
return False
|
|
101
108
|
|
|
102
109
|
############################################################
|
|
103
110
|
# BOUNDARY CONDITIONS #
|
|
@@ -125,6 +132,7 @@ class RobinBC(BoundaryCondition):
|
|
|
125
132
|
_include_stiff: bool = False
|
|
126
133
|
_include_mass: bool = False
|
|
127
134
|
_include_force: bool = False
|
|
135
|
+
_isabc: bool = False
|
|
128
136
|
|
|
129
137
|
def __init__(self, selection: GeoSurface | Selection):
|
|
130
138
|
"""A Generalization of any boundary condition of the third kind (Robin).
|
|
@@ -264,11 +272,13 @@ class AbsorbingBoundary(RobinBC):
|
|
|
264
272
|
_include_stiff: bool = True
|
|
265
273
|
_include_mass: bool = True
|
|
266
274
|
_include_force: bool = False
|
|
267
|
-
|
|
275
|
+
_isabc: bool = True
|
|
276
|
+
|
|
268
277
|
def __init__(self,
|
|
269
278
|
face: FaceSelection | GeoSurface,
|
|
270
|
-
order: int =
|
|
271
|
-
origin: tuple | None = None
|
|
279
|
+
order: int = 2,
|
|
280
|
+
origin: tuple | None = None,
|
|
281
|
+
abctype: Literal['A','B','C','D','E'] = 'B'):
|
|
272
282
|
"""Creates an AbsorbingBoundary condition.
|
|
273
283
|
|
|
274
284
|
Currently only a first order boundary condition is possible. Second order will be supported later.
|
|
@@ -286,7 +296,15 @@ class AbsorbingBoundary(RobinBC):
|
|
|
286
296
|
self.order: int = order
|
|
287
297
|
self.origin: tuple = origin
|
|
288
298
|
self.cs: CoordinateSystem = GCS
|
|
289
|
-
|
|
299
|
+
|
|
300
|
+
self.abctype: Literal['A','B','C','D','E'] = abctype
|
|
301
|
+
self.o2coeffs: tuple[float, float] = {'A': (1.0, -0.5),
|
|
302
|
+
'B': (1.00023, -0.51555),
|
|
303
|
+
'C': (1.03084, -0.73631),
|
|
304
|
+
'D': (1.06103, -0.84883),
|
|
305
|
+
'E': (1.12500, -1.00000)
|
|
306
|
+
}
|
|
307
|
+
|
|
290
308
|
def get_basis(self) -> np.ndarray:
|
|
291
309
|
return np.eye(3)
|
|
292
310
|
|
|
@@ -306,15 +324,10 @@ class AbsorbingBoundary(RobinBC):
|
|
|
306
324
|
Returns:
|
|
307
325
|
complex: The γ-constant
|
|
308
326
|
"""
|
|
309
|
-
if self.order
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
ky = k0*0.5
|
|
314
|
-
return 1j*k0*p0 - 1j*p2*ky**2/k0
|
|
315
|
-
else:
|
|
316
|
-
Factor = 1
|
|
317
|
-
return 1j*self.get_beta(k0)*Factor
|
|
327
|
+
if self.order==1:
|
|
328
|
+
return 1j*k0
|
|
329
|
+
|
|
330
|
+
return 1j*k0*self.o2coeffs[self.abctype][0]
|
|
318
331
|
|
|
319
332
|
|
|
320
333
|
@dataclass
|