emerge 0.4.7__py3-none-any.whl → 0.4.9__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 +14 -14
- emerge/_emerge/__init__.py +42 -0
- emerge/_emerge/bc.py +197 -0
- emerge/_emerge/coord.py +119 -0
- emerge/_emerge/cs.py +523 -0
- emerge/_emerge/dataset.py +36 -0
- emerge/_emerge/elements/__init__.py +19 -0
- emerge/_emerge/elements/femdata.py +212 -0
- emerge/_emerge/elements/index_interp.py +64 -0
- emerge/_emerge/elements/legrange2.py +172 -0
- emerge/_emerge/elements/ned2_interp.py +645 -0
- emerge/_emerge/elements/nedelec2.py +140 -0
- emerge/_emerge/elements/nedleg2.py +217 -0
- emerge/_emerge/geo/__init__.py +24 -0
- emerge/_emerge/geo/horn.py +107 -0
- emerge/_emerge/geo/modeler.py +449 -0
- emerge/_emerge/geo/operations.py +254 -0
- emerge/_emerge/geo/pcb.py +1244 -0
- emerge/_emerge/geo/pcb_tools/calculator.py +28 -0
- emerge/_emerge/geo/pcb_tools/macro.py +79 -0
- emerge/_emerge/geo/pmlbox.py +204 -0
- emerge/_emerge/geo/polybased.py +529 -0
- emerge/_emerge/geo/shapes.py +427 -0
- emerge/_emerge/geo/step.py +77 -0
- emerge/_emerge/geo2d.py +86 -0
- emerge/_emerge/geometry.py +510 -0
- emerge/_emerge/howto.py +214 -0
- emerge/_emerge/logsettings.py +5 -0
- emerge/_emerge/material.py +118 -0
- emerge/_emerge/mesh3d.py +730 -0
- emerge/_emerge/mesher.py +339 -0
- emerge/_emerge/mth/common_functions.py +33 -0
- emerge/_emerge/mth/integrals.py +71 -0
- emerge/_emerge/mth/optimized.py +357 -0
- emerge/_emerge/periodic.py +263 -0
- emerge/_emerge/physics/__init__.py +0 -0
- emerge/_emerge/physics/microwave/__init__.py +1 -0
- emerge/_emerge/physics/microwave/adaptive_freq.py +279 -0
- emerge/_emerge/physics/microwave/assembly/assembler.py +569 -0
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +448 -0
- emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +426 -0
- emerge/_emerge/physics/microwave/assembly/robinbc.py +433 -0
- emerge/_emerge/physics/microwave/microwave_3d.py +1150 -0
- emerge/_emerge/physics/microwave/microwave_bc.py +915 -0
- emerge/_emerge/physics/microwave/microwave_data.py +1148 -0
- emerge/_emerge/physics/microwave/periodic.py +82 -0
- emerge/_emerge/physics/microwave/port_functions.py +53 -0
- emerge/_emerge/physics/microwave/sc.py +175 -0
- emerge/_emerge/physics/microwave/simjob.py +147 -0
- emerge/_emerge/physics/microwave/sparam.py +138 -0
- emerge/_emerge/physics/microwave/touchstone.py +140 -0
- emerge/_emerge/plot/__init__.py +0 -0
- emerge/_emerge/plot/display.py +394 -0
- emerge/_emerge/plot/grapher.py +93 -0
- emerge/_emerge/plot/matplotlib/mpldisplay.py +264 -0
- emerge/_emerge/plot/pyvista/__init__.py +1 -0
- emerge/_emerge/plot/pyvista/display.py +931 -0
- emerge/_emerge/plot/pyvista/display_settings.py +24 -0
- emerge/_emerge/plot/simple_plots.py +551 -0
- emerge/_emerge/plot.py +225 -0
- emerge/_emerge/projects/__init__.py +0 -0
- emerge/_emerge/projects/_gen_base.txt +32 -0
- emerge/_emerge/projects/_load_base.txt +24 -0
- emerge/_emerge/projects/generate_project.py +40 -0
- emerge/_emerge/selection.py +596 -0
- emerge/_emerge/simmodel.py +444 -0
- emerge/_emerge/simulation_data.py +411 -0
- emerge/_emerge/solver.py +993 -0
- emerge/_emerge/system.py +54 -0
- emerge/cli.py +19 -0
- emerge/lib.py +1 -1
- emerge/plot.py +1 -1
- {emerge-0.4.7.dist-info → emerge-0.4.9.dist-info}/METADATA +7 -6
- emerge-0.4.9.dist-info/RECORD +78 -0
- emerge-0.4.9.dist-info/entry_points.txt +2 -0
- emerge-0.4.7.dist-info/RECORD +0 -9
- emerge-0.4.7.dist-info/entry_points.txt +0 -2
- {emerge-0.4.7.dist-info → emerge-0.4.9.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,448 @@
|
|
|
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
|
+
import numpy as np
|
|
19
|
+
from ....elements import Nedelec2
|
|
20
|
+
from scipy.sparse import csr_matrix, coo_matrix
|
|
21
|
+
from numba_progress import ProgressBar, ProgressBarType
|
|
22
|
+
from ....mth.optimized import local_mapping, matinv, dot_c, cross_c, compute_distances
|
|
23
|
+
from numba import c16, types, f8, i8, njit, prange
|
|
24
|
+
|
|
25
|
+
# --- CACHED FACTORIALS ---------------
|
|
26
|
+
|
|
27
|
+
_FACTORIALS = np.array([1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880], dtype=np.int64)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# --- MAPPING FUNCTIONS ---------------
|
|
31
|
+
# These mapping functions return edge and face coordinates in the appropriate order.
|
|
32
|
+
|
|
33
|
+
@njit(i8[:,:](i8[:,:], i8[:,:], i8[:,:], i8, i8), cache=True, nogil=True)
|
|
34
|
+
def local_tet_to_triid(tet_to_field, tets, tris, itet, nedges) -> np.ndarray:
|
|
35
|
+
"""Returns the triangle node indices in the right order given a tet-index"""
|
|
36
|
+
tri_ids = tet_to_field[6:10, itet] - nedges
|
|
37
|
+
global_tri_map = tris[:, tri_ids]
|
|
38
|
+
return local_mapping(tets[:, itet], global_tri_map)
|
|
39
|
+
|
|
40
|
+
@njit(i8[:,:](i8[:,:], i8[:,:], i8[:,:], i8), cache=True, nogil=True)
|
|
41
|
+
def local_tet_to_edgeid(tets, edges, tet_to_field, itet) -> np.ndarray:
|
|
42
|
+
"""Returns the edge node indices in the right order given a tet-index"""
|
|
43
|
+
global_edge_map = edges[:, tet_to_field[:6,itet]]
|
|
44
|
+
return local_mapping(tets[:, itet], global_edge_map)
|
|
45
|
+
|
|
46
|
+
@njit(i8[:,:](i8[:,:], i8[:,:], i8[:,:], i8), cache=True, nogil=True)
|
|
47
|
+
def local_tri_to_edgeid(tris, edges, tri_to_field, itri: int) -> np.ndarray:
|
|
48
|
+
"""Returns the edge node indices in the right order given a triangle-index"""
|
|
49
|
+
global_edge_map = edges[:, tri_to_field[:3,itri]]
|
|
50
|
+
return local_mapping(tris[:, itri], global_edge_map)
|
|
51
|
+
|
|
52
|
+
@njit(c16[:](c16[:,:], c16[:]), cache=True, nogil=True)
|
|
53
|
+
def matmul(Mat, Vec):
|
|
54
|
+
## Matrix multiplication of a 3D vector
|
|
55
|
+
Vout = np.empty((3,), dtype=np.complex128)
|
|
56
|
+
Vout[0] = Mat[0,0]*Vec[0] + Mat[0,1]*Vec[1] + Mat[0,2]*Vec[2]
|
|
57
|
+
Vout[1] = Mat[1,0]*Vec[0] + Mat[1,1]*Vec[1] + Mat[1,2]*Vec[2]
|
|
58
|
+
Vout[2] = Mat[2,0]*Vec[0] + Mat[2,1]*Vec[1] + Mat[2,2]*Vec[2]
|
|
59
|
+
return Vout
|
|
60
|
+
|
|
61
|
+
@njit(f8(i8, i8, i8, i8), cache=True, fastmath=True, nogil=True)
|
|
62
|
+
def volume_coeff(a: int, b: int, c: int, d: int):
|
|
63
|
+
""" Computes the appropriate matrix coefficients given a list of
|
|
64
|
+
barycentric coordinate functions mentioned.
|
|
65
|
+
Example:
|
|
66
|
+
- L1^2 * L2 - volume_coeff(1,1,2,0) """
|
|
67
|
+
klmn = np.array([0,0,0,0,0,0,0])
|
|
68
|
+
klmn[a] += 1
|
|
69
|
+
klmn[b] += 1
|
|
70
|
+
klmn[c] += 1
|
|
71
|
+
klmn[d] += 1
|
|
72
|
+
output = (_FACTORIALS[klmn[1]]*_FACTORIALS[klmn[2]]*_FACTORIALS[klmn[3]]
|
|
73
|
+
*_FACTORIALS[klmn[4]]*_FACTORIALS[klmn[5]]*_FACTORIALS[klmn[6]])/_FACTORIALS[(np.sum(klmn[1:])+3)]
|
|
74
|
+
return output
|
|
75
|
+
|
|
76
|
+
# --- PRECOMPUTE VOLUME COEFFICINETS --------------------
|
|
77
|
+
NFILL = 5
|
|
78
|
+
VOLUME_COEFF_CACHE_BASE = np.zeros((NFILL,NFILL,NFILL,NFILL), dtype=np.float64)
|
|
79
|
+
for I in range(NFILL):
|
|
80
|
+
for J in range(NFILL):
|
|
81
|
+
for K in range(NFILL):
|
|
82
|
+
for L in range(NFILL):
|
|
83
|
+
VOLUME_COEFF_CACHE_BASE[I,J,K,L] = volume_coeff(I,J,K,L)
|
|
84
|
+
|
|
85
|
+
VOLUME_COEFF_CACHE = VOLUME_COEFF_CACHE_BASE
|
|
86
|
+
|
|
87
|
+
@njit(types.Tuple((f8[:], f8[:], f8[:], f8))(f8[:], f8[:], f8[:]), cache = True, nogil=True)
|
|
88
|
+
def tet_coefficients_bcd(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray, float]:
|
|
89
|
+
"""Computes the a,b,c and d coefficients of a tet barycentric coordinate functions and the volume
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
xs (np.ndarray): The tetrahedron X-coordinates
|
|
93
|
+
ys (np.ndarray): The tetrahedron Y-coordinates
|
|
94
|
+
zs (np.ndrray): The tetrahedron Z-coordinates
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
tuple[np.ndarray, np.ndarray, np.ndarray, float]: The a, b, c, d coefficients and volume
|
|
98
|
+
"""
|
|
99
|
+
x1, x2, x3, x4 = xs
|
|
100
|
+
y1, y2, y3, y4 = ys
|
|
101
|
+
z1, z2, z3, z4 = zs
|
|
102
|
+
|
|
103
|
+
bbs = np.empty((4,), dtype=np.float64)
|
|
104
|
+
ccs = np.empty((4,), dtype=np.float64)
|
|
105
|
+
dds = np.empty((4,), dtype=np.float64)
|
|
106
|
+
|
|
107
|
+
V = np.abs(-x1*y2*z3/6 + x1*y2*z4/6 + x1*y3*z2/6 - x1*y3*z4/6 - x1*y4*z2/6 + \
|
|
108
|
+
x1*y4*z3/6 + x2*y1*z3/6 - x2*y1*z4/6 - x2*y3*z1/6 + x2*y3*z4/6 + \
|
|
109
|
+
x2*y4*z1/6 - x2*y4*z3/6 - x3*y1*z2/6 + x3*y1*z4/6 + x3*y2*z1/6 - \
|
|
110
|
+
x3*y2*z4/6 - x3*y4*z1/6 + x3*y4*z2/6 + x4*y1*z2/6 - x4*y1*z3/6 - \
|
|
111
|
+
x4*y2*z1/6 + x4*y2*z3/6 + x4*y3*z1/6 - x4*y3*z2/6)
|
|
112
|
+
|
|
113
|
+
bbs[0] = -y2*z3 + y2*z4 + y3*z2 - y3*z4 - y4*z2 + y4*z3
|
|
114
|
+
bbs[1] = y1*z3 - y1*z4 - y3*z1 + y3*z4 + y4*z1 - y4*z3
|
|
115
|
+
bbs[2] = -y1*z2 + y1*z4 + y2*z1 - y2*z4 - y4*z1 + y4*z2
|
|
116
|
+
bbs[3] = y1*z2 - y1*z3 - y2*z1 + y2*z3 + y3*z1 - y3*z2
|
|
117
|
+
ccs[0] = x2*z3 - x2*z4 - x3*z2 + x3*z4 + x4*z2 - x4*z3
|
|
118
|
+
ccs[1] = -x1*z3 + x1*z4 + x3*z1 - x3*z4 - x4*z1 + x4*z3
|
|
119
|
+
ccs[2] = x1*z2 - x1*z4 - x2*z1 + x2*z4 + x4*z1 - x4*z2
|
|
120
|
+
ccs[3] = -x1*z2 + x1*z3 + x2*z1 - x2*z3 - x3*z1 + x3*z2
|
|
121
|
+
dds[0] = -x2*y3 + x2*y4 + x3*y2 - x3*y4 - x4*y2 + x4*y3
|
|
122
|
+
dds[1] = x1*y3 - x1*y4 - x3*y1 + x3*y4 + x4*y1 - x4*y3
|
|
123
|
+
dds[2] = -x1*y2 + x1*y4 + x2*y1 - x2*y4 - x4*y1 + x4*y2
|
|
124
|
+
dds[3] = x1*y2 - x1*y3 - x2*y1 + x2*y3 + x3*y1 - x3*y2
|
|
125
|
+
|
|
126
|
+
return bbs, ccs, dds, V
|
|
127
|
+
|
|
128
|
+
def tet_mass_stiffness_matrices(field: Nedelec2,
|
|
129
|
+
er: np.ndarray,
|
|
130
|
+
ur: np.ndarray) -> tuple[csr_matrix, csr_matrix]:
|
|
131
|
+
"""Computes the curl-curl Nedelec-2 mass and stiffness matrices
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
field (Nedelec2): The Nedelec2 Field object
|
|
135
|
+
er (np.ndarray): a 3x3xN array with permittivity tensors
|
|
136
|
+
ur (np.ndarray): a 3x3xN array with permeability tensors
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
tuple[csr_matrix, csr_matrix]: The stiffness and mass matrix.
|
|
140
|
+
"""
|
|
141
|
+
tets = field.mesh.tets
|
|
142
|
+
tris = field.mesh.tris
|
|
143
|
+
edges = field.mesh.edges
|
|
144
|
+
nodes = field.mesh.nodes
|
|
145
|
+
|
|
146
|
+
nT = tets.shape[1]
|
|
147
|
+
tet_to_field = field.tet_to_field
|
|
148
|
+
tet_to_edge = field.mesh.tet_to_edge
|
|
149
|
+
nE = edges.shape[1]
|
|
150
|
+
nTri = tris.shape[1]
|
|
151
|
+
|
|
152
|
+
with ProgressBar(total=nT, ncols=100, dynamic_ncols=False) as pgb:
|
|
153
|
+
dataE, dataB, rows, cols = _matrix_builder(nodes, tets, tris, edges, field.mesh.edge_lengths, tet_to_field, tet_to_edge, ur, er, pgb)
|
|
154
|
+
|
|
155
|
+
E = coo_matrix((dataE, (rows, cols)), shape=(nE*2 + nTri*2, nE*2 + nTri*2)).tocsr()
|
|
156
|
+
B = coo_matrix((dataB, (rows, cols)), shape=(nE*2 + nTri*2, nE*2 + nTri*2)).tocsr()
|
|
157
|
+
|
|
158
|
+
return E, B
|
|
159
|
+
|
|
160
|
+
@njit(types.Tuple((c16[:,:],c16[:,:]))(f8[:,:], f8[:], i8[:,:], i8[:,:], c16[:,:], c16[:,:]), nogil=True, cache=True, parallel=False, fastmath=True)
|
|
161
|
+
def ned2_tet_stiff_mass(tet_vertices, edge_lengths, local_edge_map, local_tri_map, Ms, Mm):
|
|
162
|
+
''' Nedelec 2 tetrahedral stiffness and mass matrix submatrix Calculation
|
|
163
|
+
|
|
164
|
+
'''
|
|
165
|
+
|
|
166
|
+
Dmat = np.empty((20,20), dtype=np.complex128)
|
|
167
|
+
Fmat = np.empty((20,20), dtype=np.complex128)
|
|
168
|
+
|
|
169
|
+
xs, ys, zs = tet_vertices
|
|
170
|
+
|
|
171
|
+
bbs, ccs, dds, V = tet_coefficients_bcd(xs, ys, zs)
|
|
172
|
+
b1, b2, b3, b4 = bbs
|
|
173
|
+
c1, c2, c3, c4 = ccs
|
|
174
|
+
d1, d2, d3, d4 = dds
|
|
175
|
+
|
|
176
|
+
Ds = compute_distances(xs, ys, zs)
|
|
177
|
+
|
|
178
|
+
GL1 = np.array([b1, c1, d1]).astype(np.complex128)
|
|
179
|
+
GL2 = np.array([b2, c2, d2]).astype(np.complex128)
|
|
180
|
+
GL3 = np.array([b3, c3, d3]).astype(np.complex128)
|
|
181
|
+
GL4 = np.array([b4, c4, d4]).astype(np.complex128)
|
|
182
|
+
|
|
183
|
+
GLs = (GL1, GL2, GL3, GL4)
|
|
184
|
+
|
|
185
|
+
letters = [1,2,3,4,5,6]
|
|
186
|
+
|
|
187
|
+
KA = 1/(6*V)**4
|
|
188
|
+
KB = 1/(6*V)**2
|
|
189
|
+
|
|
190
|
+
V6 = 6*V
|
|
191
|
+
|
|
192
|
+
VOLUME_COEFF_CACHE = VOLUME_COEFF_CACHE_BASE*V6
|
|
193
|
+
for ei in range(6):
|
|
194
|
+
ei1, ei2 = local_edge_map[:, ei]
|
|
195
|
+
GA = GLs[ei1]
|
|
196
|
+
GB = GLs[ei2]
|
|
197
|
+
A, B = letters[ei1], letters[ei2]
|
|
198
|
+
L1 = edge_lengths[ei]
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
for ej in range(6):
|
|
202
|
+
ej1, ej2 = local_edge_map[:, ej]
|
|
203
|
+
|
|
204
|
+
C,D = letters[ej1], letters[ej2]
|
|
205
|
+
|
|
206
|
+
GC = GLs[ej1]
|
|
207
|
+
GD = GLs[ej2]
|
|
208
|
+
|
|
209
|
+
VAD = VOLUME_COEFF_CACHE[A,D,0,0]
|
|
210
|
+
VAC = VOLUME_COEFF_CACHE[A,C,0,0]
|
|
211
|
+
VBC = VOLUME_COEFF_CACHE[B,C,0,0]
|
|
212
|
+
VBD = VOLUME_COEFF_CACHE[B,D,0,0]
|
|
213
|
+
VABCD = VOLUME_COEFF_CACHE[A,B,C,D]
|
|
214
|
+
VABCC = VOLUME_COEFF_CACHE[A,B,C,C]
|
|
215
|
+
VABDD = VOLUME_COEFF_CACHE[A,B,D,D]
|
|
216
|
+
VBBCD = VOLUME_COEFF_CACHE[B,B,C,D]
|
|
217
|
+
VABCD = VOLUME_COEFF_CACHE[A,B,C,D]
|
|
218
|
+
VBBCD = VOLUME_COEFF_CACHE[B,B,C,D]
|
|
219
|
+
VAACD = VOLUME_COEFF_CACHE[A,A,C,D]
|
|
220
|
+
VAADD = VOLUME_COEFF_CACHE[A,A,D,D]
|
|
221
|
+
VBBCC = VOLUME_COEFF_CACHE[B,B,C,C]
|
|
222
|
+
VBBDD = VOLUME_COEFF_CACHE[B,B,D,D]
|
|
223
|
+
VAACC = VOLUME_COEFF_CACHE[A,A,C,C]
|
|
224
|
+
|
|
225
|
+
L2 = edge_lengths[ej]
|
|
226
|
+
|
|
227
|
+
BB1 = matmul(Mm,GC)
|
|
228
|
+
BC1 = matmul(Mm,GD)
|
|
229
|
+
BD1 = dot_c(GA,BB1)
|
|
230
|
+
BE1 = dot_c(GA,BC1)
|
|
231
|
+
BF1 = dot_c(GB,BB1)
|
|
232
|
+
BG1 = dot_c(GB,BC1)
|
|
233
|
+
|
|
234
|
+
Q2 = L1*L2
|
|
235
|
+
Q = Q2*9*dot_c(cross_c(GA,GB),matmul(Ms,cross_c(GC,GD)))
|
|
236
|
+
Dmat[ei+0,ej+0] = Q*VAC
|
|
237
|
+
Dmat[ei+0,ej+10] = Q*VAD
|
|
238
|
+
Dmat[ei+10,ej+0] = Q*VBC
|
|
239
|
+
Dmat[ei+10,ej+10] = Q*VBD
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
Fmat[ei+0,ej+0] = Q2*(VABCD*BD1-VABCC*BE1-VAACD*BF1+VAACC*BG1)
|
|
243
|
+
Fmat[ei+0,ej+10] = Q2*(VABDD*BD1-VABCD*BE1-VAADD*BF1+VAACD*BG1)
|
|
244
|
+
Fmat[ei+10,ej+0] = Q2*(VBBCD*BD1-VBBCC*BE1-VABCD*BF1+VABCC*BG1)
|
|
245
|
+
Fmat[ei+10,ej+10] = Q2*(VBBDD*BD1-VBBCD*BE1-VABDD*BF1+VABCD*BG1)
|
|
246
|
+
|
|
247
|
+
for ej in range(4):
|
|
248
|
+
ej1, ej2, fj = local_tri_map[:, ej]
|
|
249
|
+
|
|
250
|
+
C,D,F = letters[ej1], letters[ej2], letters[fj]
|
|
251
|
+
|
|
252
|
+
GC = GLs[ej1]
|
|
253
|
+
GD = GLs[ej2]
|
|
254
|
+
GF = GLs[fj]
|
|
255
|
+
|
|
256
|
+
VABCD = VOLUME_COEFF_CACHE[A,B,C,D]
|
|
257
|
+
VBBCD = VOLUME_COEFF_CACHE[B,B,C,D]
|
|
258
|
+
VAD = VOLUME_COEFF_CACHE[A,D,0,0]
|
|
259
|
+
VAC = VOLUME_COEFF_CACHE[A,C,0,0]
|
|
260
|
+
VAF = VOLUME_COEFF_CACHE[A,F,0,0]
|
|
261
|
+
VBF = VOLUME_COEFF_CACHE[B,F,0,0]
|
|
262
|
+
VBC = VOLUME_COEFF_CACHE[B,C,0,0]
|
|
263
|
+
VBD = VOLUME_COEFF_CACHE[B,D,0,0]
|
|
264
|
+
VABDF = VOLUME_COEFF_CACHE[A,B,D,F]
|
|
265
|
+
VABCF = VOLUME_COEFF_CACHE[A,B,F,C]
|
|
266
|
+
VAADF = VOLUME_COEFF_CACHE[A,A,D,F]
|
|
267
|
+
VAACD = VOLUME_COEFF_CACHE[A,A,C,D]
|
|
268
|
+
VBBDF = VOLUME_COEFF_CACHE[B,B,D,F]
|
|
269
|
+
VBBCD = VOLUME_COEFF_CACHE[B,B,C,D]
|
|
270
|
+
VBBCF = VOLUME_COEFF_CACHE[B,B,F,C]
|
|
271
|
+
VAACF = VOLUME_COEFF_CACHE[A,A,C,F]
|
|
272
|
+
|
|
273
|
+
Lab2 = Ds[ej1, ej2]
|
|
274
|
+
Lac2 = Ds[ej1, fj]
|
|
275
|
+
|
|
276
|
+
AB1 = cross_c(GA,GB)
|
|
277
|
+
AI1 = dot_c(AB1,matmul(Ms,cross_c(GC,GF)))
|
|
278
|
+
AJ1 = dot_c(AB1,matmul(Ms,cross_c(GD,GF)))
|
|
279
|
+
AK1 = dot_c(AB1,matmul(Ms,cross_c(GC,GD)))
|
|
280
|
+
BB1 = matmul(Mm,GF)
|
|
281
|
+
BC1 = matmul(Mm,GC)
|
|
282
|
+
BD1 = matmul(Mm,GD)
|
|
283
|
+
BE1 = dot_c(GA,BB1)
|
|
284
|
+
BF1 = dot_c(GA,BC1)
|
|
285
|
+
BG1 = dot_c(GB,BB1)
|
|
286
|
+
BH1 = dot_c(GB,BC1)
|
|
287
|
+
BI1 = dot_c(GA,BD1)
|
|
288
|
+
BJ1 = dot_c(GB,BD1)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
Dmat[ei+0,ej+6] = L1*Lac2*(-6*VAD*AI1-3*VAC*AJ1-3*VAF*AK1)
|
|
292
|
+
Dmat[ei+0,ej+16] = L1*Lab2*(6*VAF*AK1+3*VAD*AI1-3*VAC*AJ1)
|
|
293
|
+
Dmat[ei+10,ej+6] = L1*Lac2*(-6*VBD*AI1-3*VBC*AJ1-3*VBF*AK1)
|
|
294
|
+
Dmat[ei+10,ej+16] = L1*Lab2*(6*VBF*AK1+3*VBD*AI1-3*VBC*AJ1)
|
|
295
|
+
|
|
296
|
+
Fmat[ei+0,ej+6] = L1*Lac2*(VABCD*BE1-VABDF*BF1-VAACD*BG1+VAADF*BH1)
|
|
297
|
+
Fmat[ei+0,ej+16] = L1*Lab2*(VABDF*BF1-VABCF*BI1-VAADF*BH1+VAACF*BJ1)
|
|
298
|
+
Fmat[ei+10,ej+6] = L1*Lac2*(VBBCD*BE1-VBBDF*BF1-VABCD*BG1+VABDF*BH1)
|
|
299
|
+
Fmat[ei+10,ej+16] = L1*Lab2*(VBBDF*BF1-VBBCF*BI1-VABDF*BH1+VABCF*BJ1)
|
|
300
|
+
|
|
301
|
+
## Mirror the transpose part of the previous iteration as its symmetrical
|
|
302
|
+
|
|
303
|
+
Dmat[6:10, :6] = Dmat[:6, 6:10].T
|
|
304
|
+
Fmat[6:10, :6] = Fmat[:6, 6:10].T
|
|
305
|
+
Dmat[16:20, :6] = Dmat[:6, 16:20].T
|
|
306
|
+
Fmat[16:20, :6] = Fmat[:6, 16:20].T
|
|
307
|
+
Dmat[6:10, 10:16] = Dmat[10:16, 6:10].T
|
|
308
|
+
Fmat[6:10, 10:16] = Fmat[10:16, 6:10].T
|
|
309
|
+
Dmat[16:20, 10:16] = Dmat[10:16, 16:20].T
|
|
310
|
+
Fmat[16:20, 10:16] = Fmat[10:16, 16:20].T
|
|
311
|
+
|
|
312
|
+
for ei in range(4):
|
|
313
|
+
ei1, ei2, fi = local_tri_map[:, ei]
|
|
314
|
+
A, B, E = letters[ei1], letters[ei2], letters[fi]
|
|
315
|
+
GA = GLs[ei1]
|
|
316
|
+
GB = GLs[ei2]
|
|
317
|
+
GE = GLs[fi]
|
|
318
|
+
Lac1 = Ds[ei1, fi]
|
|
319
|
+
Lab1 = Ds[ei1, ei2]
|
|
320
|
+
for ej in range(4):
|
|
321
|
+
ej1, ej2, fj = local_tri_map[:, ej]
|
|
322
|
+
|
|
323
|
+
C,D,F = letters[ej1], letters[ej2], letters[fj]
|
|
324
|
+
|
|
325
|
+
GC = GLs[ej1]
|
|
326
|
+
GD = GLs[ej2]
|
|
327
|
+
GF = GLs[fj]
|
|
328
|
+
|
|
329
|
+
VABCD = VOLUME_COEFF_CACHE[A,B,C,D]
|
|
330
|
+
VAD = VOLUME_COEFF_CACHE[A,D,0,0]
|
|
331
|
+
VAC = VOLUME_COEFF_CACHE[A,C,0,0]
|
|
332
|
+
VAF = VOLUME_COEFF_CACHE[A,F,0,0]
|
|
333
|
+
VBF = VOLUME_COEFF_CACHE[B,F,0,0]
|
|
334
|
+
VBC = VOLUME_COEFF_CACHE[B,C,0,0]
|
|
335
|
+
VBD = VOLUME_COEFF_CACHE[B,D,0,0]
|
|
336
|
+
VDE = VOLUME_COEFF_CACHE[E,D,0,0]
|
|
337
|
+
VEF = VOLUME_COEFF_CACHE[E,F,0,0]
|
|
338
|
+
VCE = VOLUME_COEFF_CACHE[E,C,0,0]
|
|
339
|
+
VABDF = VOLUME_COEFF_CACHE[A,B,D,F]
|
|
340
|
+
VACEF = VOLUME_COEFF_CACHE[A,C,E,F]
|
|
341
|
+
VABCF = VOLUME_COEFF_CACHE[A,B,F,C]
|
|
342
|
+
VBCDE = VOLUME_COEFF_CACHE[B,C,D,F]
|
|
343
|
+
VBDEF = VOLUME_COEFF_CACHE[B,E,D,F]
|
|
344
|
+
VACDE = VOLUME_COEFF_CACHE[E,A,C,D]
|
|
345
|
+
VBCEF = VOLUME_COEFF_CACHE[B,E,F,C]
|
|
346
|
+
VADEF = VOLUME_COEFF_CACHE[E,A,D,F]
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
Lac2 = Ds[ej1, fj]
|
|
350
|
+
Lab2 = Ds[ej1, ej2]
|
|
351
|
+
|
|
352
|
+
AB1 = cross_c(GA,GE)
|
|
353
|
+
AF1 = cross_c(GB,GE)
|
|
354
|
+
AG1 = cross_c(GA,GB)
|
|
355
|
+
AH1 = matmul(Ms,cross_c(GC,GF))
|
|
356
|
+
AI1 = matmul(Ms,cross_c(GD,GF))
|
|
357
|
+
AJ1 = matmul(Ms,cross_c(GC,GD))
|
|
358
|
+
AK1 = dot_c(AB1,AH1)
|
|
359
|
+
AL1 = dot_c(AB1,AI1)
|
|
360
|
+
AM1 = dot_c(AB1,AJ1)
|
|
361
|
+
AN1 = dot_c(AF1,AH1)
|
|
362
|
+
AO1 = dot_c(AF1,AI1)
|
|
363
|
+
AP1 = dot_c(AF1,AJ1)
|
|
364
|
+
AQ1 = dot_c(AG1,AH1)
|
|
365
|
+
AR1 = dot_c(AG1,AI1)
|
|
366
|
+
AS1 = dot_c(AG1,AJ1)
|
|
367
|
+
BB1 = matmul(Mm,GF)
|
|
368
|
+
BC1 = matmul(Mm,GC)
|
|
369
|
+
BD1 = matmul(Mm,GD)
|
|
370
|
+
BE1 = dot_c(GE,BB1)
|
|
371
|
+
BF1 = dot_c(GE,BC1)
|
|
372
|
+
BG1 = dot_c(GA,BB1)
|
|
373
|
+
BH1 = dot_c(GA,BC1)
|
|
374
|
+
BI1 = dot_c(GE,BD1)
|
|
375
|
+
BJ1 = dot_c(GA,BD1)
|
|
376
|
+
BK1 = dot_c(GB,BB1)
|
|
377
|
+
BL1 = dot_c(GB,BC1)
|
|
378
|
+
BM1 = dot_c(GB,BD1)
|
|
379
|
+
|
|
380
|
+
Q1 = 2*VAD*AN1+VAC*AO1+VAF*AP1
|
|
381
|
+
Q2 = -2*VAF*AP1-VAD*AN1+VAC*AO1
|
|
382
|
+
Dmat[ei+6,ej+6] = Lac1*Lac2*(4*VBD*AK1+2*VBC*AL1+2*VBF*AM1+Q1+2*VDE*AQ1+VCE*AR1+VEF*AS1)
|
|
383
|
+
Dmat[ei+6,ej+16] = Lac1*Lab2*(-4*VBF*AM1-2*VBD*AK1+2*VBC*AL1+Q2-2*VEF*AS1-VDE*AQ1+VCE*AR1)
|
|
384
|
+
Dmat[ei+16,ej+6] = Lab1*Lac2*(-4*VDE*AQ1-2*VCE*AR1-2*VEF*AS1-2*VBD*AK1-VBC*AL1-VBF*AM1+Q1)
|
|
385
|
+
Dmat[ei+16,ej+16] = Lab1*Lab2*(4*VEF*AS1+2*VDE*AQ1-2*VCE*AR1+2*VBF*AM1+VBD*AK1-VBC*AL1+Q2)
|
|
386
|
+
Fmat[ei+6,ej+6] = Lac1*Lac2*(VABCD*BE1-VABDF*BF1-VBCDE*BG1+VBDEF*BH1)
|
|
387
|
+
Fmat[ei+6,ej+16] = Lac1*Lab2*(VABDF*BF1-VABCF*BI1-VBDEF*BH1+VBCEF*BJ1)
|
|
388
|
+
Fmat[ei+16,ej+6] = Lab1*Lac2*(VBCDE*BG1-VBDEF*BH1-VACDE*BK1+VADEF*BL1)
|
|
389
|
+
Fmat[ei+16,ej+16] = Lab1*Lab2*(VBDEF*BH1-VBCEF*BJ1-VADEF*BL1+VACEF*BM1)
|
|
390
|
+
|
|
391
|
+
Dmat = Dmat*KA
|
|
392
|
+
Fmat = Fmat*KB
|
|
393
|
+
|
|
394
|
+
return Dmat, Fmat
|
|
395
|
+
|
|
396
|
+
@njit(types.Tuple((c16[:], c16[:], i8[:], i8[:]))(f8[:,:],
|
|
397
|
+
i8[:,:],
|
|
398
|
+
i8[:,:],
|
|
399
|
+
i8[:,:],
|
|
400
|
+
f8[:],
|
|
401
|
+
i8[:,:],
|
|
402
|
+
i8[:,:],
|
|
403
|
+
c16[:,:,:],
|
|
404
|
+
c16[:,:,:],
|
|
405
|
+
ProgressBarType), cache=True, nogil=True, parallel=True)
|
|
406
|
+
def _matrix_builder(nodes, tets, tris, edges, all_edge_lengths, tet_to_field, tet_to_edge, ur, er, pgb: ProgressBar):
|
|
407
|
+
nT = tets.shape[1]
|
|
408
|
+
nedges = edges.shape[1]
|
|
409
|
+
|
|
410
|
+
nnz = nT*400
|
|
411
|
+
|
|
412
|
+
rows = np.empty(nnz, dtype=np.int64)
|
|
413
|
+
cols = np.empty_like(rows)
|
|
414
|
+
dataE = np.empty_like(rows, dtype=np.complex128)
|
|
415
|
+
dataB = np.empty_like(rows, dtype=np.complex128)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
for itet in prange(nT):
|
|
419
|
+
p = itet*400
|
|
420
|
+
if np.mod(itet,10)==0:
|
|
421
|
+
pgb.update(10)
|
|
422
|
+
urt = ur[:,:,itet]
|
|
423
|
+
ert = er[:,:,itet]
|
|
424
|
+
|
|
425
|
+
# Construct a local mapping to global triangle orientations
|
|
426
|
+
|
|
427
|
+
local_tri_map = local_tet_to_triid(tet_to_field, tets, tris, itet, nedges)
|
|
428
|
+
local_edge_map = local_tet_to_edgeid(tets, edges, tet_to_field, itet)
|
|
429
|
+
edge_lengths = all_edge_lengths[tet_to_edge[:,itet]]
|
|
430
|
+
|
|
431
|
+
# Construct the local edge map
|
|
432
|
+
|
|
433
|
+
Esub, Bsub = ned2_tet_stiff_mass(nodes[:,tets[:,itet]],
|
|
434
|
+
edge_lengths,
|
|
435
|
+
local_edge_map,
|
|
436
|
+
local_tri_map,
|
|
437
|
+
matinv(urt), ert)
|
|
438
|
+
|
|
439
|
+
indices = tet_to_field[:, itet]
|
|
440
|
+
for ii in range(20):
|
|
441
|
+
rows[p+20*ii:p+20*(ii+1)] = indices[ii]
|
|
442
|
+
cols[p+ii:p+400+ii:20] = indices[ii]
|
|
443
|
+
|
|
444
|
+
dataE[p:p+400] = Esub.ravel()
|
|
445
|
+
dataB[p:p+400] = Bsub.ravel()
|
|
446
|
+
return dataE, dataB, rows, cols
|
|
447
|
+
|
|
448
|
+
|