emerge 1.1.0__py3-none-any.whl → 1.1.1__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 -1
- emerge/_emerge/const.py +2 -1
- emerge/_emerge/elements/ned2_interp.py +122 -42
- emerge/_emerge/geo/__init__.py +1 -1
- emerge/_emerge/geo/operations.py +20 -0
- emerge/_emerge/geo/pcb.py +34 -16
- emerge/_emerge/geo/shapes.py +1 -0
- emerge/_emerge/geo/step.py +177 -41
- emerge/_emerge/geometry.py +166 -19
- emerge/_emerge/material.py +2 -0
- emerge/_emerge/mesh3d.py +1 -3
- emerge/_emerge/mesher.py +33 -9
- emerge/_emerge/mth/common_functions.py +1 -1
- emerge/_emerge/mth/optimized.py +2 -2
- emerge/_emerge/physics/microwave/adaptive_mesh.py +437 -95
- emerge/_emerge/physics/microwave/assembly/assembler.py +9 -1
- emerge/_emerge/physics/microwave/microwave_3d.py +2 -2
- emerge/_emerge/physics/microwave/microwave_bc.py +1 -0
- emerge/_emerge/physics/microwave/microwave_data.py +94 -5
- emerge/_emerge/plot/pyvista/display.py +10 -7
- emerge/_emerge/selection.py +17 -2
- emerge/_emerge/simmodel.py +76 -25
- emerge/_emerge/solver.py +3 -3
- {emerge-1.1.0.dist-info → emerge-1.1.1.dist-info}/METADATA +1 -1
- {emerge-1.1.0.dist-info → emerge-1.1.1.dist-info}/RECORD +28 -28
- {emerge-1.1.0.dist-info → emerge-1.1.1.dist-info}/WHEEL +0 -0
- {emerge-1.1.0.dist-info → emerge-1.1.1.dist-info}/entry_points.txt +0 -0
- {emerge-1.1.0.dist-info → emerge-1.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,6 +20,66 @@ import numpy as np
|
|
|
20
20
|
from ...mth.optimized import matmul, outward_normal, cross_c
|
|
21
21
|
from numba import njit, f8, c16, i8, types, prange # type: ignore, p
|
|
22
22
|
from loguru import logger
|
|
23
|
+
from ...const import C0, MU0, EPS0
|
|
24
|
+
|
|
25
|
+
@njit(cache=True, nogil=True)
|
|
26
|
+
def diam_circum_circle(v1: np.ndarray, v2: np.ndarray, v3: np.ndarray, eps: float = 1e-14) -> float:
|
|
27
|
+
"""
|
|
28
|
+
Diameter of the circumcircle of triangle (v1,v2,v3) in 3D.
|
|
29
|
+
Uses D = (|AB|*|AC|*|BC|) / ||AB x AC||.
|
|
30
|
+
Returns np.inf if points are (near) collinear.
|
|
31
|
+
"""
|
|
32
|
+
AB = v2 - v1
|
|
33
|
+
AC = v3 - v1
|
|
34
|
+
BC = v3 - v2
|
|
35
|
+
|
|
36
|
+
a = np.linalg.norm(BC)
|
|
37
|
+
b = np.linalg.norm(AC)
|
|
38
|
+
c = np.linalg.norm(AB)
|
|
39
|
+
|
|
40
|
+
cross = np.cross(AB, AC)
|
|
41
|
+
denom = np.linalg.norm(cross) # 2 * area of triangle
|
|
42
|
+
|
|
43
|
+
if denom < eps:
|
|
44
|
+
return np.inf # degenerate/collinear
|
|
45
|
+
|
|
46
|
+
return (a * b * c) / denom # diameter = 2R
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@njit(cache=True, nogil=True)
|
|
50
|
+
def circum_sphere_diam(v1: np.ndarray, v2: np.ndarray, v3: np.ndarray, v4: np.ndarray, eps: float = 1e-14) -> float:
|
|
51
|
+
"""
|
|
52
|
+
Diameter of the circumsphere of tetrahedron (v1,v2,v3,v4) in 3D.
|
|
53
|
+
Solves for center c from 2*(pi - p4) · c = |pi|^2 - |p4|^2, i=1..3.
|
|
54
|
+
Returns np.inf if points are (near) coplanar/degenerate.
|
|
55
|
+
"""
|
|
56
|
+
p1, p2, p3, p4 = v1, v2, v3, v4
|
|
57
|
+
|
|
58
|
+
M = np.empty((3, 3), dtype=np.float64)
|
|
59
|
+
M[0, :] = 2.0 * (p1 - p4)
|
|
60
|
+
M[1, :] = 2.0 * (p2 - p4)
|
|
61
|
+
M[2, :] = 2.0 * (p3 - p4)
|
|
62
|
+
|
|
63
|
+
# manual 3x3 determinant (Numba-friendly)
|
|
64
|
+
det = (
|
|
65
|
+
M[0,0] * (M[1,1]*M[2,2] - M[1,2]*M[2,1])
|
|
66
|
+
- M[0,1] * (M[1,0]*M[2,2] - M[1,2]*M[2,0])
|
|
67
|
+
+ M[0,2] * (M[1,0]*M[2,1] - M[1,1]*M[2,0])
|
|
68
|
+
)
|
|
69
|
+
if np.abs(det) < eps:
|
|
70
|
+
return np.inf # coplanar/degenerate
|
|
71
|
+
|
|
72
|
+
rhs = np.empty(3, dtype=np.float64)
|
|
73
|
+
rhs[0] = np.dot(p1, p1) - np.dot(p4, p4)
|
|
74
|
+
rhs[1] = np.dot(p2, p2) - np.dot(p4, p4)
|
|
75
|
+
rhs[2] = np.dot(p3, p3) - np.dot(p4, p4)
|
|
76
|
+
|
|
77
|
+
# Solve for circumcenter
|
|
78
|
+
c = np.linalg.solve(M, rhs)
|
|
79
|
+
|
|
80
|
+
# Radius = distance to any vertex
|
|
81
|
+
R = np.linalg.norm(c - p1)
|
|
82
|
+
return 2.0 * R # diameter
|
|
23
83
|
|
|
24
84
|
def print_sparam_matrix(pre: str, S: np.ndarray):
|
|
25
85
|
"""
|
|
@@ -40,7 +100,7 @@ def print_sparam_matrix(pre: str, S: np.ndarray):
|
|
|
40
100
|
phase_deg = np.degrees(np.angle(S[i, j]))
|
|
41
101
|
row_str.append(f"{mag_db:6.2f} dB ∠ {phase_deg:6.1f}°")
|
|
42
102
|
logger.debug(" | ".join(row_str))
|
|
43
|
-
|
|
103
|
+
|
|
44
104
|
def compute_convergence(Sold: np.ndarray, Snew: np.ndarray) -> float:
|
|
45
105
|
"""
|
|
46
106
|
Return a single scalar: max |Snew - Sold|.
|
|
@@ -61,37 +121,51 @@ def compute_convergence(Sold: np.ndarray, Snew: np.ndarray) -> float:
|
|
|
61
121
|
|
|
62
122
|
def select_refinement_indices(errors: np.ndarray, refine: float) -> np.ndarray:
|
|
63
123
|
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Returns indices sorted from largest to smallest |error|.
|
|
68
|
-
"""
|
|
69
|
-
errs = np.abs(np.ravel(errors))
|
|
70
|
-
N = errs.size
|
|
71
|
-
if N == 0:
|
|
72
|
-
return np.array([], dtype=int)
|
|
73
|
-
refine = float(np.clip(refine, 0.0, 1.0))
|
|
74
|
-
if refine == 0.0:
|
|
75
|
-
return np.array([], dtype=int)
|
|
124
|
+
Dörfler marking:
|
|
125
|
+
Choose the minimal number of elements whose squared error sum
|
|
126
|
+
reaches at least 'refine' (theta in [0,1]) of the global squared error.
|
|
76
127
|
|
|
77
|
-
|
|
78
|
-
|
|
128
|
+
Args:
|
|
129
|
+
errors: 1D or ND array of local error indicators (nonnegative).
|
|
130
|
+
refine: theta in [0,1]; fraction of total error energy to target.
|
|
79
131
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
132
|
+
Returns:
|
|
133
|
+
np.ndarray of indices (ints) sorted by decreasing error.
|
|
134
|
+
"""
|
|
135
|
+
# Flatten and sanitize
|
|
136
|
+
errs = np.abs(np.ravel(errors).astype(float))
|
|
137
|
+
n = errs.size
|
|
138
|
+
if n == 0:
|
|
139
|
+
return np.empty(0, dtype=int)
|
|
140
|
+
|
|
141
|
+
errs[~np.isfinite(errs)] = 0.0 # replace NaN/inf by 0
|
|
142
|
+
theta = float(np.clip(refine, 0.0, 1.0))
|
|
143
|
+
if theta <= 0.0:
|
|
144
|
+
return np.empty(0, dtype=int)
|
|
145
|
+
|
|
146
|
+
# Dörfler uses squared indicators
|
|
147
|
+
ind = errs * errs
|
|
148
|
+
total = ind.sum()
|
|
149
|
+
if total <= 0.0:
|
|
150
|
+
return np.empty(0, dtype=int)
|
|
151
|
+
|
|
152
|
+
# Sort by decreasing indicator
|
|
153
|
+
order = np.argsort(ind)[::-1]
|
|
154
|
+
sum_error = 0
|
|
155
|
+
indices = []
|
|
156
|
+
for index in order:
|
|
157
|
+
sum_error += ind[index]
|
|
158
|
+
indices.append(index)
|
|
159
|
+
if sum_error >= refine*total:
|
|
160
|
+
break
|
|
161
|
+
|
|
162
|
+
#cum = np.cumsum(ind[order])
|
|
83
163
|
|
|
84
|
-
#
|
|
85
|
-
|
|
86
|
-
B = sorted_desc[:k]
|
|
164
|
+
# Smallest m with cumulative ≥ theta * total
|
|
165
|
+
#m = int(np.searchsorted(cum, theta * total, side="left")) + 1
|
|
87
166
|
|
|
88
|
-
#
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# Return chosen indices sorted from largest to smallest amplitude
|
|
92
|
-
mask = np.zeros(N, dtype=bool)
|
|
93
|
-
mask[chosen] = True
|
|
94
|
-
return sorted_desc[mask[sorted_desc]]
|
|
167
|
+
#chosen = order[:m] # already from largest to smallest
|
|
168
|
+
return np.array(indices)#chosen.astype(int)
|
|
95
169
|
|
|
96
170
|
@njit(f8[:](i8, f8[:,:], f8, f8, f8[:]), cache=True, nogil=True, parallel=False)
|
|
97
171
|
def compute_size(id: int, coords: np.ndarray, q: float, scaler: float, dss: np.ndarray) -> float:
|
|
@@ -114,7 +188,7 @@ def compute_size(id: int, coords: np.ndarray, q: float, scaler: float, dss: np.n
|
|
|
114
188
|
if n == id:
|
|
115
189
|
sizes[n] = dss[n]*scaler
|
|
116
190
|
continue
|
|
117
|
-
nsize = scaler*dss[n]/q - (1-q)/q * ((x-coords[0,n])**2 + (y-coords[1,n])**2 + (z-coords[2,n])**2)**0.5
|
|
191
|
+
nsize = scaler*dss[n]/q - (1-q)/q * max(0, (((x-coords[0,n])**2 + (y-coords[1,n])**2 + (z-coords[2,n])**2)**0.5-dss[n]/3))
|
|
118
192
|
sizes[n] = nsize
|
|
119
193
|
return sizes
|
|
120
194
|
|
|
@@ -167,7 +241,7 @@ def reduce_point_set(coords: np.ndarray, q: float, dss: np.ndarray, scaler: floa
|
|
|
167
241
|
if (N-counter)/N < keep_percentage:
|
|
168
242
|
break
|
|
169
243
|
|
|
170
|
-
n_imposed = np.sum(impressed_size[:,i] <= (current_min*1.
|
|
244
|
+
n_imposed = np.sum(impressed_size[:,i] <= (current_min*1.3))
|
|
171
245
|
|
|
172
246
|
if n_imposed == 0:
|
|
173
247
|
include[i] = 0
|
|
@@ -257,16 +331,42 @@ def tet_coefficients(xs, ys, zs):
|
|
|
257
331
|
|
|
258
332
|
return aas, bbs, ccs, dds, V
|
|
259
333
|
|
|
260
|
-
|
|
334
|
+
DPTS_2D = np.array([[0.22338159, 0.22338159, 0.22338159, 0.10995174, 0.10995174,
|
|
335
|
+
0.10995174],
|
|
336
|
+
[0.10810302, 0.44594849, 0.44594849, 0.81684757, 0.09157621,
|
|
337
|
+
0.09157621],
|
|
338
|
+
[0.44594849, 0.44594849, 0.10810302, 0.09157621, 0.09157621,
|
|
339
|
+
0.81684757],
|
|
340
|
+
[0.44594849, 0.10810302, 0.44594849, 0.09157621, 0.81684757,
|
|
341
|
+
0.09157621]], dtype=np.float64)
|
|
342
|
+
|
|
343
|
+
DPTS_3D = np.array([[-0.078933 , 0.04573333, 0.04573333, 0.04573333, 0.04573333,
|
|
344
|
+
0.14933333, 0.14933333, 0.14933333, 0.14933333, 0.14933333,
|
|
345
|
+
0.14933333],
|
|
346
|
+
[ 0.25 , 0.78571429, 0.07142857, 0.07142857, 0.07142857,
|
|
347
|
+
0.39940358, 0.39940358, 0.39940358, 0.10059642, 0.10059642,
|
|
348
|
+
0.10059642],
|
|
349
|
+
[ 0.25 , 0.07142857, 0.07142857, 0.07142857, 0.78571429,
|
|
350
|
+
0.10059642, 0.10059642, 0.39940358, 0.39940358, 0.39940358,
|
|
351
|
+
0.10059642],
|
|
352
|
+
[ 0.25 , 0.07142857, 0.07142857, 0.78571429, 0.07142857,
|
|
353
|
+
0.39940358, 0.10059642, 0.10059642, 0.39940358, 0.10059642,
|
|
354
|
+
0.39940358],
|
|
355
|
+
[ 0.25 , 0.07142857, 0.78571429, 0.07142857, 0.07142857,
|
|
356
|
+
0.10059642, 0.39940358, 0.10059642, 0.10059642, 0.39940358,
|
|
357
|
+
0.39940358]], dtype=np.float64)
|
|
358
|
+
|
|
359
|
+
@njit(c16[:,:](f8[:,:], f8[:,:], c16[:], i8[:,:], i8[:,:]), cache=True, nogil=True)
|
|
261
360
|
def compute_field(coords: np.ndarray,
|
|
262
361
|
vertices: np.ndarray,
|
|
263
362
|
Etet: np.ndarray,
|
|
264
363
|
l_edge_ids: np.ndarray,
|
|
265
364
|
l_tri_ids: np.ndarray):
|
|
266
365
|
|
|
267
|
-
x = coords[0]
|
|
268
|
-
y = coords[1]
|
|
269
|
-
z = coords[2]
|
|
366
|
+
x = coords[0,:]
|
|
367
|
+
y = coords[1,:]
|
|
368
|
+
z = coords[2,:]
|
|
369
|
+
N = coords.shape[1]
|
|
270
370
|
|
|
271
371
|
xvs = vertices[0,:]
|
|
272
372
|
yvs = vertices[1,:]
|
|
@@ -279,11 +379,12 @@ def compute_field(coords: np.ndarray,
|
|
|
279
379
|
Em2s = Etet[10:16]
|
|
280
380
|
Ef2s = Etet[16:20]
|
|
281
381
|
|
|
282
|
-
Exl =
|
|
283
|
-
Eyl =
|
|
284
|
-
Ezl =
|
|
382
|
+
Exl = np.zeros_like(x, dtype=np.complex128)
|
|
383
|
+
Eyl = np.zeros_like(x, dtype=np.complex128)
|
|
384
|
+
Ezl = np.zeros_like(x, dtype=np.complex128)
|
|
385
|
+
|
|
386
|
+
V1 = (6*V)**3
|
|
285
387
|
|
|
286
|
-
V1 = (216*V**3)
|
|
287
388
|
for ie in range(6):
|
|
288
389
|
Em1, Em2 = Em1s[ie], Em2s[ie]
|
|
289
390
|
edgeids = l_edge_ids[:, ie]
|
|
@@ -334,10 +435,10 @@ def compute_field(coords: np.ndarray,
|
|
|
334
435
|
Eyl += ey
|
|
335
436
|
Ezl += ez
|
|
336
437
|
|
|
337
|
-
out = np.zeros((3,), dtype=np.complex128)
|
|
338
|
-
out[0] = Exl
|
|
339
|
-
out[1] = Eyl
|
|
340
|
-
out[2] = Ezl
|
|
438
|
+
out = np.zeros((3,N), dtype=np.complex128)
|
|
439
|
+
out[0,:] = Exl
|
|
440
|
+
out[1,:] = Eyl
|
|
441
|
+
out[2,:] = Ezl
|
|
341
442
|
return out
|
|
342
443
|
|
|
343
444
|
@njit(c16[:,:](f8[:,:], f8[:,:], c16[:], i8[:,:], i8[:,:]), cache=True, nogil=True)
|
|
@@ -366,8 +467,8 @@ def compute_curl(coords: np.ndarray,
|
|
|
366
467
|
Eyl = np.zeros((x.shape[0],), dtype=np.complex128)
|
|
367
468
|
Ezl = np.zeros((x.shape[0],), dtype=np.complex128)
|
|
368
469
|
|
|
369
|
-
V1 =
|
|
370
|
-
V2 =
|
|
470
|
+
V1 = 216*V**3
|
|
471
|
+
V2 = 72*V**3
|
|
371
472
|
|
|
372
473
|
for ie in range(6):
|
|
373
474
|
Em1, Em2 = Em1s[ie], Em2s[ie]
|
|
@@ -461,8 +562,103 @@ def compute_curl(coords: np.ndarray,
|
|
|
461
562
|
out[2,:] = Ezl
|
|
462
563
|
return out
|
|
463
564
|
|
|
464
|
-
@njit(c16[:](f8[
|
|
465
|
-
def
|
|
565
|
+
@njit(c16[:](f8[:,:], f8[:,:], c16[:], i8[:,:], i8[:,:], c16[:,:]), cache=True, nogil=True)
|
|
566
|
+
def compute_div(coords: np.ndarray,
|
|
567
|
+
vertices: np.ndarray,
|
|
568
|
+
Etet: np.ndarray,
|
|
569
|
+
l_edge_ids: np.ndarray,
|
|
570
|
+
l_tri_ids: np.ndarray,
|
|
571
|
+
Um: np.ndarray):
|
|
572
|
+
|
|
573
|
+
uxx, uxy, uxz = Um[0,0], Um[0,1], Um[0,2]
|
|
574
|
+
uyx, uyy, uyz = Um[1,0], Um[1,1], Um[1,2]
|
|
575
|
+
uzx, uzy, uzz = Um[2,0], Um[2,1], Um[2,2]
|
|
576
|
+
|
|
577
|
+
xs = coords[0,:]
|
|
578
|
+
ys = coords[1,:]
|
|
579
|
+
zs = coords[2,:]
|
|
580
|
+
|
|
581
|
+
xvs = vertices[0,:]
|
|
582
|
+
yvs = vertices[1,:]
|
|
583
|
+
zvs = vertices[2,:]
|
|
584
|
+
|
|
585
|
+
a_s, b_s, c_s, d_s, V = tet_coefficients(xvs, yvs, zvs)
|
|
586
|
+
|
|
587
|
+
Em1s = Etet[0:6]
|
|
588
|
+
Ef1s = Etet[6:10]
|
|
589
|
+
Em2s = Etet[10:16]
|
|
590
|
+
Ef2s = Etet[16:20]
|
|
591
|
+
|
|
592
|
+
difE = np.zeros((xs.shape[0],), dtype=np.complex128)
|
|
593
|
+
|
|
594
|
+
V1 = (216*V**3)
|
|
595
|
+
V2 = (72*V**3)
|
|
596
|
+
|
|
597
|
+
for ie in range(6):
|
|
598
|
+
Em1, Em2 = Em1s[ie], Em2s[ie]
|
|
599
|
+
edgeids = l_edge_ids[:, ie]
|
|
600
|
+
a1, a2 = a_s[edgeids]
|
|
601
|
+
b1, b2 = b_s[edgeids]
|
|
602
|
+
c1, c2 = c_s[edgeids]
|
|
603
|
+
d1, d2 = d_s[edgeids]
|
|
604
|
+
x1, x2 = xvs[edgeids]
|
|
605
|
+
y1, y2 = yvs[edgeids]
|
|
606
|
+
z1, z2 = zvs[edgeids]
|
|
607
|
+
|
|
608
|
+
L = np.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)
|
|
609
|
+
C1 = (a2 + b2*xs + c2*ys + d2*zs)
|
|
610
|
+
C2 = (a1 + b1*xs + c1*ys + d1*zs)
|
|
611
|
+
C3 = (b1*C1 - b2*C2)
|
|
612
|
+
C4 = (c1*C1 - c2*C2)
|
|
613
|
+
C5 = (d1*C1 - d2*C2)
|
|
614
|
+
C6 = (b1*c2 - b2*c1)
|
|
615
|
+
C7 = (c1*d2 - c2*d1)
|
|
616
|
+
C8 = (b1*d2 - b2*d1)
|
|
617
|
+
difE += (Em1*L*(b1*uxx*C3 + b1*uxy*C4 + b1*uxz*C5 + c1*uyx*C3 + c1*uyy*C4 + c1*uyz*C5 + d1*uzx*C3
|
|
618
|
+
+ d1*uzy*C4 + d1*uzz*C5 - uxy*C6*C2 - uxz*C8*C2 + uyx*C6*C2 - uyz*C7*C2 + uzx*C8*C2 + uzy*C7*C2) +
|
|
619
|
+
Em2*L*(b2*uxx*C3 + b2*uxy*C4 + b2*uxz*C5 + c2*uyx*C3 + c2*uyy*C4 + c2*uyz*C5 + d2*uzx*C3
|
|
620
|
+
+ d2*uzy*C4 + d2*uzz*C5 - uxy*C6*C1 - uxz*C8*C1 + uyx*C6*C1 - uyz*C7*C1 + uzx*C8*C1 + uzy*C7*C1))/V1
|
|
621
|
+
|
|
622
|
+
for ie in range(4):
|
|
623
|
+
Em1, Em2 = Ef1s[ie], Ef2s[ie]
|
|
624
|
+
triids = l_tri_ids[:, ie]
|
|
625
|
+
a1, a2, a3 = a_s[triids]
|
|
626
|
+
b1, b2, b3 = b_s[triids]
|
|
627
|
+
c1, c2, c3 = c_s[triids]
|
|
628
|
+
d1, d2, d3 = d_s[triids]
|
|
629
|
+
|
|
630
|
+
x1, x2, x3 = xvs[l_tri_ids[:, ie]]
|
|
631
|
+
y1, y2, y3 = yvs[l_tri_ids[:, ie]]
|
|
632
|
+
z1, z2, z3 = zvs[l_tri_ids[:, ie]]
|
|
633
|
+
|
|
634
|
+
L1 = np.sqrt((x1-x3)**2 + (y1-y3)**2 + (z1-z3)**2)
|
|
635
|
+
L2 = np.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)
|
|
636
|
+
C1 = (a3 + b3*xs + c3*ys + d3*zs)
|
|
637
|
+
C2 = (a1 + b1*xs + c1*ys + d1*zs)
|
|
638
|
+
C6 = (a2 + b2*xs + c2*ys + d2*zs)
|
|
639
|
+
C3 = (b1*C1 - b3*C2)
|
|
640
|
+
C4 = (c1*C1 - c3*C2)
|
|
641
|
+
C5 = (d1*C1 - d3*C2)
|
|
642
|
+
C7 = (b1*c3 - b3*c1)
|
|
643
|
+
C8 = (b1*d3 - b3*d1)
|
|
644
|
+
C9 = (c1*d3 - c3*d1)
|
|
645
|
+
C10 = (b1*C6 - b2*C2)
|
|
646
|
+
C11 = (c1*C6 - c2*C2)
|
|
647
|
+
C12 = (d1*C6 - d2*C2)
|
|
648
|
+
C13 = (b1*c2 - b2*c1)
|
|
649
|
+
C14 = (b1*d2 - b2*d1)
|
|
650
|
+
C15 = (c1*d2 - c2*d1)
|
|
651
|
+
|
|
652
|
+
difE += (-Em1*L1*(b2*uxx*C3 + b2*uxy*C4 + b2*uxz*C5 + c2*uyx*C3 + c2*uyy*C4 + c2*uyz*C5 + d2*uzx*C3
|
|
653
|
+
+ d2*uzy*C4 + d2*uzz*C5 - uxy*C7*C6 - uxz*C8*C6 + uyx*C7*C6 - uyz*C9*C6 + uzx*C8*C6 + uzy*C9*C6)
|
|
654
|
+
+ Em2*L2*(b3*uxx*C10 + b3*uxy*C11 + b3*uxz*C12 + c3*uyx*C10 + c3*uyy*C11 + c3*uyz*C12
|
|
655
|
+
+ d3*uzx*C10 + d3*uzy*C11 + d3*uzz*C12 - uxy*C13*C1 - uxz*C14*C1 + uyx*C13*C1 - uyz*C15*C1 + uzx*C14*C1 + uzy*C15*C1))/V1
|
|
656
|
+
|
|
657
|
+
return difE
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
@njit(c16[:](f8[:,:], c16[:], i8[:,:], i8[:,:], c16[:,:]), cache=True, nogil=True)
|
|
661
|
+
def compute_curl_curl(
|
|
466
662
|
vertices: np.ndarray,
|
|
467
663
|
Etet: np.ndarray,
|
|
468
664
|
l_edge_ids: np.ndarray,
|
|
@@ -473,10 +669,6 @@ def compute_curl_curl(coords: np.ndarray,
|
|
|
473
669
|
uyx, uyy, uyz = Um[1,0], Um[1,1], Um[1,2]
|
|
474
670
|
uzx, uzy, uzz = Um[2,0], Um[2,1], Um[2,2]
|
|
475
671
|
|
|
476
|
-
x = coords[0]
|
|
477
|
-
y = coords[1]
|
|
478
|
-
z = coords[2]
|
|
479
|
-
|
|
480
672
|
xvs = vertices[0,:]
|
|
481
673
|
yvs = vertices[1,:]
|
|
482
674
|
zvs = vertices[2,:]
|
|
@@ -492,7 +684,7 @@ def compute_curl_curl(coords: np.ndarray,
|
|
|
492
684
|
Em2s = Etet[10:16]
|
|
493
685
|
Ef2s = Etet[16:20]
|
|
494
686
|
|
|
495
|
-
V1 = (
|
|
687
|
+
V1 = (6*V)**3
|
|
496
688
|
|
|
497
689
|
for ie in range(6):
|
|
498
690
|
Em1, Em2 = Em1s[ie], Em2s[ie]
|
|
@@ -510,9 +702,9 @@ def compute_curl_curl(coords: np.ndarray,
|
|
|
510
702
|
ey = 3*L1*(Em1*(b1**2*c2*uzz - b1**2*d2*uzy - b1*b2*c1*uzz + b1*b2*d1*uzy + b1*c1*d2*uzx - b1*c2*d1*uxz - b1*c2*d1*uzx + b1*d1*d2*uxy + b2*c1*d1*uxz - b2*d1**2*uxy - c1*d1*d2*uxx + c2*d1**2*uxx) + Em2*(b1*b2*c2*uzz - b1*b2*d2*uzy - b1*c2*d2*uxz + b1*d2**2*uxy - b2**2*c1*uzz + b2**2*d1*uzy + b2*c1*d2*uxz + b2*c1*d2*uzx - b2*c2*d1*uzx - b2*d1*d2*uxy - c1*d2**2*uxx + c2*d1*d2*uxx))
|
|
511
703
|
ez = -3*L1*(Em1*(b1**2*c2*uyz - b1**2*d2*uyy - b1*b2*c1*uyz + b1*b2*d1*uyy - b1*c1*c2*uxz + b1*c1*d2*uxy + b1*c1*d2*uyx - b1*c2*d1*uyx + b2*c1**2*uxz - b2*c1*d1*uxy - c1**2*d2*uxx + c1*c2*d1*uxx) + Em2*(b1*b2*c2*uyz - b1*b2*d2*uyy - b1*c2**2*uxz + b1*c2*d2*uxy - b2**2*c1*uyz + b2**2*d1*uyy + b2*c1*c2*uxz + b2*c1*d2*uyx - b2*c2*d1*uxy - b2*c2*d1*uyx - c1*c2*d2*uxx + c2**2*d1*uxx))
|
|
512
704
|
|
|
513
|
-
Exl += ex
|
|
514
|
-
Eyl += ey
|
|
515
|
-
Ezl += ez
|
|
705
|
+
Exl += ex/V1
|
|
706
|
+
Eyl += ey/V1
|
|
707
|
+
Ezl += ez/V1
|
|
516
708
|
|
|
517
709
|
for ie in range(4):
|
|
518
710
|
Em1, Em2 = Ef1s[ie], Ef2s[ie]
|
|
@@ -529,13 +721,13 @@ def compute_curl_curl(coords: np.ndarray,
|
|
|
529
721
|
L1 = np.sqrt((x1-x3)**2 + (y1-y3)**2 + (z1-z3)**2)
|
|
530
722
|
L2 = np.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)
|
|
531
723
|
|
|
532
|
-
ex =
|
|
533
|
-
ey =
|
|
534
|
-
ez = -
|
|
724
|
+
ex = (Em1*L1*(3*c2*uzx*(c1*d3 - c3*d1) + 3*c2*uzz*(b1*c3 - b3*c1) - 3*d2*uyx*(c1*d3 - c3*d1) + 3*d2*uyy*(b1*d3 - b3*d1) - uyz*(-b2*(c1*d3 - c3*d1) + c2*(b1*d3 - b3*d1) + 2*d2*(b1*c3 - b3*c1)) - uzy*(b2*(c1*d3 - c3*d1) + 2*c2*(b1*d3 - b3*d1) + d2*(b1*c3 - b3*c1))) - Em2*L2*(3*c3*uzx*(c1*d2 - c2*d1) + 3*c3*uzz*(b1*c2 - b2*c1) - 3*d3*uyx*(c1*d2 - c2*d1) + 3*d3*uyy*(b1*d2 - b2*d1) - uyz*(-b3*(c1*d2 - c2*d1) + c3*(b1*d2 - b2*d1) + 2*d3*(b1*c2 - b2*c1)) - uzy*(b3*(c1*d2 - c2*d1) + 2*c3*(b1*d2 - b2*d1) + d3*(b1*c2 - b2*c1))))
|
|
725
|
+
ey = (Em1*L1*(3*b2*uzy*(b1*d3 - b3*d1) - 3*b2*uzz*(b1*c3 - b3*c1) + 3*d2*uxx*(c1*d3 - c3*d1) - 3*d2*uxy*(b1*d3 - b3*d1) + uxz*(-b2*(c1*d3 - c3*d1) + c2*(b1*d3 - b3*d1) + 2*d2*(b1*c3 - b3*c1)) - uzx*(2*b2*(c1*d3 - c3*d1) + c2*(b1*d3 - b3*d1) - d2*(b1*c3 - b3*c1))) - Em2*L2*(3*b3*uzy*(b1*d2 - b2*d1) - 3*b3*uzz*(b1*c2 - b2*c1) + 3*d3*uxx*(c1*d2 - c2*d1) - 3*d3*uxy*(b1*d2 - b2*d1) + uxz*(-b3*(c1*d2 - c2*d1) + c3*(b1*d2 - b2*d1) + 2*d3*(b1*c2 - b2*c1)) - uzx*(2*b3*(c1*d2 - c2*d1) + c3*(b1*d2 - b2*d1) - d3*(b1*c2 - b2*c1))))
|
|
726
|
+
ez = -(Em1*L1*(3*b2*uyy*(b1*d3 - b3*d1) - 3*b2*uyz*(b1*c3 - b3*c1) + 3*c2*uxx*(c1*d3 - c3*d1) + 3*c2*uxz*(b1*c3 - b3*c1) - uxy*(b2*(c1*d3 - c3*d1) + 2*c2*(b1*d3 - b3*d1) + d2*(b1*c3 - b3*c1)) - uyx*(2*b2*(c1*d3 - c3*d1) + c2*(b1*d3 - b3*d1) - d2*(b1*c3 - b3*c1))) - Em2*L2*(3*b3*uyy*(b1*d2 - b2*d1) - 3*b3*uyz*(b1*c2 - b2*c1) + 3*c3*uxx*(c1*d2 - c2*d1) + 3*c3*uxz*(b1*c2 - b2*c1) - uxy*(b3*(c1*d2 - c2*d1) + 2*c3*(b1*d2 - b2*d1) + d3*(b1*c2 - b2*c1)) - uyx*(2*b3*(c1*d2 - c2*d1) + c3*(b1*d2 - b2*d1) - d3*(b1*c2 - b2*c1))))
|
|
535
727
|
|
|
536
|
-
Exl += ex
|
|
537
|
-
Eyl += ey
|
|
538
|
-
Ezl += ez
|
|
728
|
+
Exl += ex/V1
|
|
729
|
+
Eyl += ey/V1
|
|
730
|
+
Ezl += ez/V1
|
|
539
731
|
|
|
540
732
|
out = np.zeros((3,), dtype=np.complex128)
|
|
541
733
|
out[0] = Exl
|
|
@@ -543,9 +735,40 @@ def compute_curl_curl(coords: np.ndarray,
|
|
|
543
735
|
out[2] = Ezl
|
|
544
736
|
return out
|
|
545
737
|
|
|
738
|
+
@njit(c16[:,:](c16[:], c16[:,:]), cache=True, fastmath=True, nogil=True)
|
|
739
|
+
def cross_c_arry(a: np.ndarray, b: np.ndarray):
|
|
740
|
+
"""Optimized complex single vector cross product
|
|
741
|
+
|
|
742
|
+
Args:
|
|
743
|
+
a (np.ndarray): (3,) vector a
|
|
744
|
+
b (np.ndarray): (3,) vector b
|
|
745
|
+
|
|
746
|
+
Returns:
|
|
747
|
+
np.ndarray: a ⨉ b
|
|
748
|
+
"""
|
|
749
|
+
crossv = np.empty((3,b.shape[1]), dtype=np.complex128)
|
|
750
|
+
crossv[0,:] = a[1]*b[2,:] - a[2]*b[1,:]
|
|
751
|
+
crossv[1,:] = a[2]*b[0,:] - a[0]*b[2,:]
|
|
752
|
+
crossv[2,:] = a[0]*b[1,:] - a[1]*b[0,:]
|
|
753
|
+
return crossv
|
|
754
|
+
|
|
755
|
+
@njit(c16[:](c16[:], c16[:,:]), cache=True, fastmath=True, nogil=True)
|
|
756
|
+
def dot_c_arry(a: np.ndarray, b: np.ndarray):
|
|
757
|
+
"""Optimized complex single vector cross product
|
|
758
|
+
|
|
759
|
+
Args:
|
|
760
|
+
a (np.ndarray): (3,) vector a
|
|
761
|
+
b (np.ndarray): (3,) vector b
|
|
762
|
+
|
|
763
|
+
Returns:
|
|
764
|
+
np.ndarray: a ⨉ b
|
|
765
|
+
"""
|
|
766
|
+
dotv = a[0]*b[0,:] + a[1]*b[1,:] + a[2]*b[2,:]
|
|
767
|
+
return dotv
|
|
768
|
+
|
|
546
769
|
@njit(types.Tuple((f8[:], f8[:]))(f8[:,:], i8[:,:], i8[:,:], i8[:,:], f8[:,:],
|
|
547
770
|
c16[:], f8[:], f8[:], i8[:,:], i8[:,:],
|
|
548
|
-
f8[:,:], i8[:,:], i8[:,:], c16[:], c16[:], f8), cache=True, nogil=True)
|
|
771
|
+
f8[:,:], i8[:,:], i8[:,:], c16[:], c16[:], i8[:], f8), cache=True, nogil=True)
|
|
549
772
|
def compute_error_single(nodes, tets, tris, edges, centers,
|
|
550
773
|
Efield,
|
|
551
774
|
edge_lengths,
|
|
@@ -557,83 +780,200 @@ def compute_error_single(nodes, tets, tris, edges, centers,
|
|
|
557
780
|
tet_to_field,
|
|
558
781
|
er,
|
|
559
782
|
ur,
|
|
783
|
+
pec_tris,
|
|
560
784
|
k0,) -> np.ndarray:
|
|
561
785
|
|
|
786
|
+
is_pec = np.zeros((tris.shape[1],), dtype=np.bool)
|
|
787
|
+
is_pec[pec_tris] = True
|
|
562
788
|
|
|
563
|
-
#
|
|
789
|
+
# CONSTANTS
|
|
564
790
|
ntet = tets.shape[1]
|
|
565
791
|
nedges = edges.shape[1]
|
|
792
|
+
W0 = k0*C0
|
|
793
|
+
N2D = DPTS_2D.shape[1]
|
|
794
|
+
W_VOL = DPTS_3D[0,:]
|
|
795
|
+
Y0 = np.sqrt(1/MU0)
|
|
566
796
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
error = np.zeros((ntet,), dtype=np.float64)
|
|
797
|
+
# INIT POSTERIORI ERROR ESTIMATE QUANTITIES
|
|
798
|
+
alpha_t = np.zeros((ntet,), dtype=np.complex128)
|
|
570
799
|
max_elem_size = np.zeros((ntet,), dtype=np.float64)
|
|
571
800
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
801
|
+
Qf_face1 = np.zeros((4,N2D,ntet), dtype=np.complex128)
|
|
802
|
+
Qf_face2 = np.zeros((4,N2D,ntet), dtype=np.complex128)
|
|
803
|
+
Jf_face1 = np.zeros((4,3,N2D,ntet), dtype=np.complex128)
|
|
804
|
+
Jf_face2 = np.zeros((4,3,N2D,ntet), dtype=np.complex128)
|
|
805
|
+
|
|
806
|
+
areas_fr = np.zeros((4, N2D, ntet), dtype=np.float64)
|
|
807
|
+
Rf_fr = np.zeros((4, ntet), dtype=np.float64)
|
|
808
|
+
adj_tets_mat = -np.ones((4,ntet), dtype=np.int32)
|
|
576
809
|
|
|
577
|
-
|
|
578
810
|
# Compute Error estimate
|
|
579
811
|
for itet in range(ntet):
|
|
580
812
|
uinv = (1/ur[itet])*np.eye(3)
|
|
581
813
|
ermat = er[itet]*np.eye(3)
|
|
814
|
+
erc = er[itet]
|
|
815
|
+
urc = ur[itet]
|
|
582
816
|
|
|
817
|
+
# GEOMETRIC QUANTITIES
|
|
583
818
|
vertices = nodes[:,tets[:, itet]]
|
|
819
|
+
v1 = vertices[:,0]
|
|
820
|
+
v2 = vertices[:,1]
|
|
821
|
+
v3 = vertices[:,2]
|
|
822
|
+
v4 = vertices[:,3]
|
|
823
|
+
|
|
824
|
+
# VOLUME INTEGRATION POINTS
|
|
825
|
+
vxs = DPTS_3D[1,:]*v1[0] + DPTS_3D[2,:]*v2[0] + DPTS_3D[3,:]*v3[0] + DPTS_3D[4,:]*v4[0]
|
|
826
|
+
vys = DPTS_3D[1,:]*v1[1] + DPTS_3D[2,:]*v2[1] + DPTS_3D[3,:]*v3[1] + DPTS_3D[4,:]*v4[1]
|
|
827
|
+
vzs = DPTS_3D[1,:]*v1[2] + DPTS_3D[2,:]*v2[2] + DPTS_3D[3,:]*v3[2] + DPTS_3D[4,:]*v4[2]
|
|
584
828
|
|
|
829
|
+
intpts = np.empty((3,DPTS_3D.shape[1]), dtype=np.float64)
|
|
830
|
+
intpts[0,:] = vxs
|
|
831
|
+
intpts[1,:] = vys
|
|
832
|
+
intpts[2,:] = vzs
|
|
833
|
+
|
|
834
|
+
# TET TRI NODE COUPLINGS
|
|
585
835
|
g_node_ids = tets[:, itet]
|
|
586
836
|
g_edge_ids = edges[:, tet_to_field[:6, itet]]
|
|
587
837
|
g_tri_ids = tris[:, tet_to_field[6:10, itet]-nedges]
|
|
588
|
-
|
|
589
838
|
l_edge_ids = local_mapping(g_node_ids, g_edge_ids)
|
|
590
839
|
l_tri_ids = local_mapping(g_node_ids, g_tri_ids)
|
|
591
|
-
|
|
592
|
-
coords = centers[:,itet]
|
|
593
|
-
Ef = Efield[tet_to_field[:,itet]]
|
|
594
|
-
Rv1 = -compute_curl_curl(coords, vertices, Ef, l_edge_ids, l_tri_ids, uinv)
|
|
595
|
-
Rv2 = k0**2*(ermat @ compute_field(coords, vertices, Ef, l_edge_ids, l_tri_ids))
|
|
596
|
-
|
|
597
840
|
triids = tet_to_tri[:,itet]
|
|
598
|
-
|
|
841
|
+
|
|
842
|
+
size_max = circum_sphere_diam(v1,v2,v3,v4)
|
|
843
|
+
#size_max = np.max(edge_lengths[tet_to_edge[:,itet]])
|
|
599
844
|
|
|
600
845
|
Volume = compute_volume(vertices[0,:], vertices[1,:], vertices[2,:])
|
|
601
|
-
|
|
602
|
-
|
|
846
|
+
|
|
847
|
+
Rt = size_max
|
|
848
|
+
# Efield
|
|
849
|
+
Ef = Efield[tet_to_field[:,itet]]
|
|
850
|
+
|
|
851
|
+
# Qt term
|
|
852
|
+
Qt = Volume*EPS0*np.sum(W_VOL*compute_div(intpts, vertices, Ef, l_edge_ids, l_tri_ids, ermat), axis=0)
|
|
853
|
+
|
|
854
|
+
# Jt term
|
|
855
|
+
|
|
856
|
+
Rv1 = compute_curl_curl(vertices, Ef, l_edge_ids, l_tri_ids, uinv)
|
|
857
|
+
Rv2 = -k0**2*(ermat @ compute_field(intpts, vertices, Ef, l_edge_ids, l_tri_ids))
|
|
858
|
+
Rv = 1*Rv2
|
|
859
|
+
Rv[0,:] += Rv1[0] # X-component
|
|
860
|
+
Rv[1,:] += Rv1[1] # Y-component
|
|
861
|
+
Rv[2,:] += Rv1[2] # Z-component
|
|
862
|
+
|
|
863
|
+
Rv[0,:] = Rv[0,:]*W_VOL
|
|
864
|
+
Rv[1,:] = Rv[1,:]*W_VOL
|
|
865
|
+
Rv[2,:] = Rv[2,:]*W_VOL
|
|
866
|
+
|
|
867
|
+
Jt = -Volume*np.sum(1/(1j*W0*MU0) * Rv, axis=1)
|
|
868
|
+
|
|
869
|
+
Gt = (1j*W0*np.exp(-1j*k0*Rt)/(4*np.pi*Rt))
|
|
870
|
+
alpha_t[itet] = - Gt/(erc*EPS0) * Qt*Qt - Gt*urc*MU0 * np.sum(Jt*Jt)
|
|
871
|
+
|
|
872
|
+
# Face Residual computation
|
|
873
|
+
|
|
874
|
+
all_face_coords = np.empty((3,4*N2D), dtype=np.float64)
|
|
875
|
+
for itri in range(4):
|
|
876
|
+
triid = triids[itri]
|
|
877
|
+
tnodes = nodes[:,tris[:,triid]]
|
|
878
|
+
n1 = tnodes[:,0]
|
|
879
|
+
n2 = tnodes[:,1]
|
|
880
|
+
n3 = tnodes[:,2]
|
|
881
|
+
all_face_coords[0,itri*N2D:(itri+1)*N2D] = DPTS_2D[1,:]*n1[0] + DPTS_2D[2,:]*n2[0] + DPTS_2D[3,:]*n3[0]
|
|
882
|
+
all_face_coords[1,itri*N2D:(itri+1)*N2D] = DPTS_2D[1,:]*n1[1] + DPTS_2D[2,:]*n2[1] + DPTS_2D[3,:]*n3[1]
|
|
883
|
+
all_face_coords[2,itri*N2D:(itri+1)*N2D] = DPTS_2D[1,:]*n1[2] + DPTS_2D[2,:]*n2[2] + DPTS_2D[3,:]*n3[2]
|
|
884
|
+
|
|
885
|
+
Qf_all = erc*EPS0*compute_field(all_face_coords, vertices, Ef, l_edge_ids, l_tri_ids)
|
|
886
|
+
Jf_all = -1/(1j*MU0*W0)*matmul(uinv, compute_curl(all_face_coords, vertices, Ef, l_edge_ids, l_tri_ids))
|
|
887
|
+
E_face_all = compute_field(all_face_coords, vertices, Ef, l_edge_ids, l_tri_ids)
|
|
603
888
|
tetc = centers[:,itet].flatten()
|
|
604
889
|
|
|
605
|
-
max_elem_size[itet] =
|
|
890
|
+
max_elem_size[itet] = size_max
|
|
606
891
|
|
|
607
892
|
for iface in range(4):
|
|
608
|
-
|
|
893
|
+
tri_index = triids[iface]
|
|
894
|
+
|
|
895
|
+
pec_face = is_pec[tri_index]
|
|
896
|
+
|
|
897
|
+
i1, i2, i3 = tris[:, tri_index]
|
|
898
|
+
|
|
899
|
+
slc1 = iface*N2D
|
|
900
|
+
slc2 = slc1+N2D
|
|
901
|
+
|
|
609
902
|
normal = outward_normal(nodes[:,i1], nodes[:,i2], nodes[:,i3], tetc).astype(np.complex128)
|
|
610
903
|
|
|
904
|
+
area = areas[triids[iface]]
|
|
905
|
+
|
|
906
|
+
n1 = nodes[:,i1]
|
|
907
|
+
n2 = nodes[:,i2]
|
|
908
|
+
n3 = nodes[:,i3]
|
|
909
|
+
l1 = np.linalg.norm(n2-n1)
|
|
910
|
+
l2 = np.linalg.norm(n3-n1)
|
|
911
|
+
l3 = np.linalg.norm(n3-n2)
|
|
912
|
+
Rf = np.max(np.array([l1, l2, l3]))
|
|
913
|
+
Rf = diam_circum_circle(n1,n2,n3)
|
|
914
|
+
Rf_fr[iface,itet] = Rf
|
|
915
|
+
areas_fr[iface, :, itet] = area
|
|
916
|
+
|
|
611
917
|
adj_tets = [int(tri_to_tet[j,triids[iface]]) for j in range(2)]
|
|
612
918
|
adj_tets = [num for num in adj_tets if num not in (itet, -1234)]
|
|
613
919
|
|
|
614
920
|
if len(adj_tets) == 0:
|
|
615
921
|
continue
|
|
616
|
-
area = areas[triids[iface]]
|
|
617
922
|
|
|
618
|
-
|
|
923
|
+
if pec_face is True:
|
|
924
|
+
Jtan = Y0*np.sqrt(1/urc)*cross_c_arry(normal, -cross_c_arry(normal, E_face_all[:, slc1: slc2]))
|
|
925
|
+
|
|
926
|
+
itet_adj = adj_tets[0]
|
|
927
|
+
iface_adj = np.argwhere(tet_to_tri[:,itet_adj]==triids[iface])[0][0]
|
|
928
|
+
|
|
929
|
+
Jf_face1[iface, :, :, itet] = Jtan
|
|
930
|
+
|
|
931
|
+
adj_tets_mat[iface,itet] = itet_adj
|
|
932
|
+
continue
|
|
619
933
|
|
|
620
934
|
itet_adj = adj_tets[0]
|
|
621
935
|
iface_adj = np.argwhere(tet_to_tri[:,itet_adj]==triids[iface])[0][0]
|
|
622
936
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
937
|
+
Jf_face1[iface, :, :, itet] = cross_c_arry(normal, Jf_all[:, slc1:slc2])
|
|
938
|
+
Jf_face2[iface_adj, :, :, itet_adj] = -cross_c_arry(normal, Jf_all[:, slc1:slc2])
|
|
939
|
+
|
|
940
|
+
Qf_face1[iface, :, itet] = dot_c_arry(normal, Qf_all[:, slc1:slc2])
|
|
941
|
+
Qf_face2[iface_adj, :, itet_adj] = -dot_c_arry(normal, Qf_all[:, slc1:slc2])
|
|
626
942
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
fdiff = np.abs(face_error1 - face_error2)
|
|
630
|
-
fnorm = fdiff[:,0,:]**2 + fdiff[:,1,:]**2 + fdiff[:,2,:]**2
|
|
631
|
-
ferror = np.sum(fnorm*hfs, axis=0)
|
|
632
|
-
error = hks**2*error + 0.5*ferror
|
|
943
|
+
adj_tets_mat[iface,itet] = itet_adj
|
|
633
944
|
|
|
945
|
+
# Compute 2D Gauss quadrature weight matrix
|
|
946
|
+
fWs = np.empty_like(areas_fr, dtype=np.float64)
|
|
947
|
+
for i in range(N2D):
|
|
948
|
+
fWs[:,i,:] = DPTS_2D[0,i]
|
|
949
|
+
|
|
950
|
+
# Compute the εE field difference (4, NDPTS, NTET)
|
|
951
|
+
Qf_delta = Qf_face1 - Qf_face2
|
|
952
|
+
Jf_delta = Jf_face1 - Jf_face2
|
|
953
|
+
|
|
954
|
+
# Perform Gauss-Quadrature integration (4, NTET)
|
|
955
|
+
Qf_int = np.sum(Qf_delta*areas_fr*fWs, axis=1)
|
|
956
|
+
Jf_int_x = np.sum(Jf_delta[:,0,:,:]*areas_fr*fWs, axis=1)
|
|
957
|
+
Jf_int_y = np.sum(Jf_delta[:,1,:,:]*areas_fr*fWs, axis=1)
|
|
958
|
+
Jf_int_z = np.sum(Jf_delta[:,2,:,:]*areas_fr*fWs, axis=1)
|
|
959
|
+
|
|
960
|
+
Gf = (1j*W0*np.exp(-1j*k0*Rf_fr)/(4*np.pi*Rf_fr))
|
|
961
|
+
alpha_Df = - Gf/(er*EPS0)*(Qf_int*Qf_int) - Gf*(ur*MU0) * (Jf_int_x*Jf_int_x + Jf_int_y*Jf_int_y + Jf_int_z*Jf_int_z)
|
|
962
|
+
|
|
963
|
+
alpha_Nf = np.zeros((4, ntet), dtype=np.complex128)
|
|
964
|
+
for it in range(ntet):
|
|
965
|
+
for iface in range(4):
|
|
966
|
+
it2 = adj_tets_mat[iface, it]
|
|
967
|
+
if it2==-1:
|
|
968
|
+
continue
|
|
969
|
+
alpha_Nf[iface,it] = alpha_t[it2]
|
|
970
|
+
|
|
971
|
+
alpha_f = np.sum((alpha_t/(alpha_t + alpha_Nf + 1e-13))*alpha_Df, axis=0)
|
|
972
|
+
error = (np.abs(alpha_t + alpha_f))**0.5
|
|
973
|
+
|
|
634
974
|
return error, max_elem_size
|
|
635
975
|
|
|
636
|
-
def compute_error_estimate(field: MWField) -> np.ndarray:
|
|
976
|
+
def compute_error_estimate(field: MWField, pec_tris: list[int]) -> np.ndarray:
|
|
637
977
|
mesh = field.mesh
|
|
638
978
|
|
|
639
979
|
nodes = mesh.nodes
|
|
@@ -650,8 +990,10 @@ def compute_error_estimate(field: MWField) -> np.ndarray:
|
|
|
650
990
|
tet_to_field = field.basis.tet_to_field
|
|
651
991
|
er = field._der
|
|
652
992
|
ur = field._dur
|
|
993
|
+
|
|
653
994
|
Ls = mesh.edge_lengths
|
|
654
995
|
|
|
996
|
+
pec_tris = np.sort(np.unique(np.array(pec_tris)))
|
|
655
997
|
errors = []
|
|
656
998
|
for key in field._fields.keys():
|
|
657
999
|
excitation = field._fields[key]
|
|
@@ -659,7 +1001,7 @@ def compute_error_estimate(field: MWField) -> np.ndarray:
|
|
|
659
1001
|
error, sizes = compute_error_single(nodes, tets, tris, edges,
|
|
660
1002
|
centers, excitation, Ls, As,
|
|
661
1003
|
tet_to_edge, tet_to_tri, tri_centers,
|
|
662
|
-
tri_to_tet, tet_to_field, er, ur, field.k0)
|
|
1004
|
+
tri_to_tet, tet_to_field, er, ur, pec_tris, field.k0)
|
|
663
1005
|
|
|
664
1006
|
errors.append(error)
|
|
665
1007
|
|