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
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
# <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
|
-
from ..microwave_bc import PEC, BoundaryCondition, RectangularWaveguide, RobinBC, PortBC, Periodic
|
|
19
|
+
from ..microwave_bc import PEC, BoundaryCondition, RectangularWaveguide, RobinBC, PortBC, Periodic, MWBoundaryConditionSet
|
|
20
20
|
from ....elements.nedelec2 import Nedelec2
|
|
21
21
|
from ....elements.nedleg2 import NedelecLegrange2
|
|
22
22
|
from ....mth.optimized import gaus_quad_tri
|
|
@@ -26,14 +26,7 @@ from scipy.sparse import csr_matrix
|
|
|
26
26
|
from loguru import logger
|
|
27
27
|
from ..simjob import SimJob
|
|
28
28
|
from .periodicbc import gen_periodic_matrix
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
############################################################
|
|
32
|
-
# CONSTANTS #
|
|
33
|
-
############################################################
|
|
34
|
-
|
|
35
|
-
C0 = 299792458
|
|
36
|
-
EPS0 = 8.854187818814e-12
|
|
29
|
+
from ....const import MU0, EPS0, C0
|
|
37
30
|
|
|
38
31
|
|
|
39
32
|
############################################################
|
|
@@ -124,7 +117,7 @@ class Assembler:
|
|
|
124
117
|
sig: np.ndarray,
|
|
125
118
|
k0: float,
|
|
126
119
|
port: PortBC,
|
|
127
|
-
|
|
120
|
+
bc_set: MWBoundaryConditionSet) -> tuple[csr_matrix, csr_matrix, np.ndarray, NedelecLegrange2]:
|
|
128
121
|
"""Computes the boundary mode analysis matrices
|
|
129
122
|
|
|
130
123
|
Args:
|
|
@@ -134,32 +127,37 @@ class Assembler:
|
|
|
134
127
|
sig (np.ndarray): The conductivity scalar of shape (N,)
|
|
135
128
|
k0 (float): The simulation phase constant
|
|
136
129
|
port (PortBC): The port boundary condition object
|
|
137
|
-
bcs (
|
|
130
|
+
bcs (MWBoundaryConditionSet): The other boundary conditions
|
|
138
131
|
|
|
139
132
|
Returns:
|
|
140
133
|
tuple[np.ndarray, np.ndarray, np.ndarray, NedelecLegrange2]: The E, B, solve ids and Mixed order field object.
|
|
141
134
|
"""
|
|
142
135
|
from .generalized_eigen import generelized_eigenvalue_matrix
|
|
143
|
-
|
|
136
|
+
logger.debug('Assembling Boundary Mode Matrices')
|
|
137
|
+
|
|
138
|
+
bcs = bc_set.boundary_conditions
|
|
144
139
|
mesh = field.mesh
|
|
145
140
|
tri_ids = mesh.get_triangles(port.tags)
|
|
141
|
+
logger.trace(f'.boundary face has {len(tri_ids)} triangles.')
|
|
146
142
|
|
|
147
143
|
origin = tuple([c-n for c,n in zip(port.cs.origin, port.cs.gzhat)])
|
|
148
|
-
|
|
144
|
+
logger.trace(f'.boundary origin {origin}')
|
|
145
|
+
|
|
149
146
|
boundary_surface = mesh.boundary_surface(port.tags, origin)
|
|
150
147
|
nedlegfield = NedelecLegrange2(boundary_surface, port.cs)
|
|
151
148
|
|
|
152
149
|
ermesh = er[:,:,tri_ids]
|
|
153
150
|
urmesh = ur[:,:,tri_ids]
|
|
154
151
|
sigmesh = sig[tri_ids]
|
|
155
|
-
|
|
156
152
|
ermesh = ermesh - 1j * sigmesh/(k0*C0*EPS0)
|
|
157
153
|
|
|
154
|
+
logger.trace(f'.assembling matrices for {nedlegfield} at k0={k0:.2f}')
|
|
158
155
|
E, B = generelized_eigenvalue_matrix(nedlegfield, ermesh, urmesh, port.cs._basis, k0)
|
|
159
156
|
|
|
160
|
-
|
|
157
|
+
# TODO: Simplified to all "conductors" loosely defined. Must change to implementing line robin boundary conditions.
|
|
158
|
+
pecs: list[BoundaryCondition] = bc_set.get_conductors()#[bc for bc in bcs if isinstance(bc,PEC)]
|
|
161
159
|
if len(pecs) > 0:
|
|
162
|
-
logger.debug('
|
|
160
|
+
logger.debug(f'.total of equiv. {len(pecs)} PEC BCs implemented')
|
|
163
161
|
|
|
164
162
|
pec_ids = []
|
|
165
163
|
|
|
@@ -172,8 +170,8 @@ class Assembler:
|
|
|
172
170
|
pec_edges = []
|
|
173
171
|
pec_vertices = []
|
|
174
172
|
for pec in pecs:
|
|
173
|
+
logger.trace(f'.implementing {pec}')
|
|
175
174
|
face_tags = pec.tags
|
|
176
|
-
|
|
177
175
|
tri_ids = mesh.get_triangles(face_tags)
|
|
178
176
|
edge_ids = list(mesh.tri_to_edge[:,tri_ids].flatten())
|
|
179
177
|
for ii in edge_ids:
|
|
@@ -186,7 +184,6 @@ class Assembler:
|
|
|
186
184
|
pec_vertices.append(eids[3]-nedlegfield.n_xy)
|
|
187
185
|
pec_vertices.append(eids[4]-nedlegfield.n_xy)
|
|
188
186
|
|
|
189
|
-
|
|
190
187
|
for ii in tri_ids:
|
|
191
188
|
i2 = nedlegfield.mesh.from_source_tri(ii)
|
|
192
189
|
if i2 is None:
|
|
@@ -194,12 +191,11 @@ class Assembler:
|
|
|
194
191
|
tids = nedlegfield.tri_to_field[:, i2]
|
|
195
192
|
pec_ids.extend(list(tids))
|
|
196
193
|
|
|
197
|
-
port._field = nedlegfield
|
|
198
|
-
port._pece = pec_edges
|
|
199
|
-
port._pecv = pec_vertices
|
|
200
194
|
# Process all port boundary Conditions
|
|
201
|
-
|
|
202
|
-
|
|
195
|
+
pec_ids_set: set[int] = set(pec_ids)
|
|
196
|
+
|
|
197
|
+
logger.trace(f'.total of {len(pec_ids_set)} pec DoF to remove.')
|
|
198
|
+
solve_ids = [i for i in range(nedlegfield.n_field) if i not in pec_ids_set]
|
|
203
199
|
|
|
204
200
|
return E, B, np.array(solve_ids), nedlegfield
|
|
205
201
|
|
|
@@ -234,16 +230,16 @@ class Assembler:
|
|
|
234
230
|
|
|
235
231
|
mesh = field.mesh
|
|
236
232
|
er = er - 1j*sig/(W0*EPS0)*np.repeat(np.eye(3)[:, :, np.newaxis], er.shape[2], axis=2)
|
|
237
|
-
is_frequency_dependent: bool = np.any((sig > 0) & (sig < self.conductivity_limit))
|
|
233
|
+
is_frequency_dependent: bool = np.any((sig > 0) & (sig < self.conductivity_limit)) # type: ignore
|
|
238
234
|
|
|
239
235
|
|
|
240
236
|
if cache_matrices and not is_frequency_dependent and self.cached_matrices is not None:
|
|
241
237
|
# IF CACHED AND AVAILABLE PULL E AND B FROM CACHE
|
|
242
|
-
logger.debug('
|
|
238
|
+
logger.debug('Using cached matricies.')
|
|
243
239
|
E, B = self.cached_matrices
|
|
244
240
|
else:
|
|
245
241
|
# OTHERWISE, COMPUTE
|
|
246
|
-
logger.debug('
|
|
242
|
+
logger.debug('Assembling matrices')
|
|
247
243
|
E, B = tet_mass_stiffness_matrices(field, er, ur)
|
|
248
244
|
self.cached_matrices = (E, B)
|
|
249
245
|
|
|
@@ -254,7 +250,7 @@ class Assembler:
|
|
|
254
250
|
|
|
255
251
|
# ISOLATE BOUNDARY CONDITIONS TO ASSEMBLE
|
|
256
252
|
pec_bcs: list[PEC] = [bc for bc in bcs if isinstance(bc,PEC)]
|
|
257
|
-
robin_bcs: list[
|
|
253
|
+
robin_bcs: list[RobinBC] = [bc for bc in bcs if isinstance(bc,RobinBC)]
|
|
258
254
|
port_bcs: list[PortBC] = [bc for bc in bcs if isinstance(bc, PortBC)]
|
|
259
255
|
periodic_bcs: list[Periodic] = [bc for bc in bcs if isinstance(bc, Periodic)]
|
|
260
256
|
|
|
@@ -262,15 +258,24 @@ class Assembler:
|
|
|
262
258
|
b = np.zeros((E.shape[0],)).astype(np.complex128)
|
|
263
259
|
port_vectors = {port.port_number: np.zeros((E.shape[0],)).astype(np.complex128) for port in port_bcs}
|
|
264
260
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
261
|
+
|
|
262
|
+
############################################################
|
|
263
|
+
# PEC BOUNDARY CONDITIONS #
|
|
264
|
+
############################################################
|
|
265
|
+
|
|
266
|
+
logger.debug('Implementing PEC Boundary Conditions.')
|
|
267
|
+
pec_ids: list[int] = []
|
|
268
268
|
# Conductivity above al imit, consider it all PEC
|
|
269
|
+
ipec = 0
|
|
269
270
|
for itet in range(field.n_tets):
|
|
270
271
|
if sig[itet] > self.conductivity_limit:
|
|
272
|
+
ipec+=1
|
|
271
273
|
pec_ids.extend(field.tet_to_field[:,itet])
|
|
272
|
-
|
|
274
|
+
if ipec>0:
|
|
275
|
+
logger.trace(f'Extended PEC with {ipec} tets with a conductivity > {self.conductivity_limit}.')
|
|
276
|
+
|
|
273
277
|
for pec in pec_bcs:
|
|
278
|
+
logger.trace(f'Implementing: {pec}')
|
|
274
279
|
if len(pec.tags)==0:
|
|
275
280
|
continue
|
|
276
281
|
face_tags = pec.tags
|
|
@@ -285,14 +290,18 @@ class Assembler:
|
|
|
285
290
|
tids = field.tri_to_field[:, ii]
|
|
286
291
|
pec_ids.extend(list(tids))
|
|
287
292
|
|
|
288
|
-
|
|
293
|
+
|
|
294
|
+
############################################################
|
|
295
|
+
# ROBIN BOUNDARY CONDITIONS #
|
|
296
|
+
############################################################
|
|
297
|
+
|
|
289
298
|
if len(robin_bcs) > 0:
|
|
290
|
-
logger.debug('
|
|
299
|
+
logger.debug('Implementing Robin Boundary Conditions.')
|
|
291
300
|
|
|
292
301
|
gauss_points = gaus_quad_tri(4)
|
|
293
302
|
Bempty = field.empty_tri_matrix()
|
|
294
303
|
for bc in robin_bcs:
|
|
295
|
-
|
|
304
|
+
logger.trace(f'.Implementing {bc}')
|
|
296
305
|
for tag in bc.tags:
|
|
297
306
|
face_tags = [tag,]
|
|
298
307
|
|
|
@@ -301,6 +310,7 @@ class Assembler:
|
|
|
301
310
|
edge_ids = list(mesh.tri_to_edge[:,tri_ids].flatten())
|
|
302
311
|
|
|
303
312
|
gamma = bc.get_gamma(K0)
|
|
313
|
+
logger.trace(f'..robin bc γ={gamma:.3f}')
|
|
304
314
|
|
|
305
315
|
def Ufunc(x,y):
|
|
306
316
|
return bc.get_Uinc(x,y,K0)
|
|
@@ -309,38 +319,42 @@ class Assembler:
|
|
|
309
319
|
if ibasis is None:
|
|
310
320
|
basis = plane_basis_from_points(mesh.nodes[:,nodes]) + 1e-16
|
|
311
321
|
ibasis = np.linalg.pinv(basis)
|
|
322
|
+
logger.trace(f'..Using computed basis: {ibasis.flatten()}')
|
|
312
323
|
if bc._include_force:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
port_vectors[bc.port_number] += b_p
|
|
317
|
-
|
|
324
|
+
Bempty, b_p = assemble_robin_bc_excited(field, Bempty, tri_ids, Ufunc, gamma, ibasis, bc.cs.origin, gauss_points) # type: ignore
|
|
325
|
+
port_vectors[bc.port_number] += b_p # type: ignore
|
|
326
|
+
logger.trace(f'..included force vector term with norm {np.linalg.norm(b_p):.3f}')
|
|
318
327
|
else:
|
|
319
|
-
Bempty = assemble_robin_bc(field, Bempty, tri_ids, gamma)
|
|
328
|
+
Bempty = assemble_robin_bc(field, Bempty, tri_ids, gamma) # type: ignore
|
|
320
329
|
B_p = field.generate_csr(Bempty)
|
|
321
330
|
K = K + B_p
|
|
322
331
|
|
|
323
332
|
if len(periodic_bcs) > 0:
|
|
324
|
-
logger.debug('
|
|
333
|
+
logger.debug('Implementing Periodic Boundary Conditions.')
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
############################################################
|
|
337
|
+
# PERIODIC BOUNDARY CONDITIONS #
|
|
338
|
+
############################################################
|
|
325
339
|
|
|
326
|
-
|
|
327
|
-
# Periodic BCs
|
|
328
340
|
Pmats = []
|
|
329
|
-
remove = set()
|
|
341
|
+
remove: set[int] = set()
|
|
330
342
|
has_periodic = False
|
|
331
343
|
|
|
332
|
-
for
|
|
344
|
+
for pbc in periodic_bcs:
|
|
345
|
+
logger.trace(f'.Implementing {pbc}')
|
|
333
346
|
has_periodic = True
|
|
334
|
-
tri_ids_1 = mesh.get_triangles(
|
|
335
|
-
edge_ids_1 = mesh.get_edges(
|
|
336
|
-
tri_ids_2 = mesh.get_triangles(
|
|
337
|
-
edge_ids_2 = mesh.get_edges(
|
|
338
|
-
dv = np.array(
|
|
347
|
+
tri_ids_1 = mesh.get_triangles(pbc.face1.tags)
|
|
348
|
+
edge_ids_1 = mesh.get_edges(pbc.face1.tags)
|
|
349
|
+
tri_ids_2 = mesh.get_triangles(pbc.face2.tags)
|
|
350
|
+
edge_ids_2 = mesh.get_edges(pbc.face2.tags)
|
|
351
|
+
dv = np.array(pbc.dv)
|
|
352
|
+
logger.trace(f'..displacement vector {dv}')
|
|
339
353
|
linked_tris = pair_coordinates(mesh.tri_centers, tri_ids_1, tri_ids_2, dv, 1e-9)
|
|
340
354
|
linked_edges = pair_coordinates(mesh.edge_centers, edge_ids_1, edge_ids_2, dv, 1e-9)
|
|
341
|
-
dv = np.array(
|
|
342
|
-
phi =
|
|
343
|
-
|
|
355
|
+
dv = np.array(pbc.dv)
|
|
356
|
+
phi = pbc.phi(K0)
|
|
357
|
+
logger.trace(f'..ϕ={phi} rad/m')
|
|
344
358
|
Pmat, rows = gen_periodic_matrix(tri_ids_1,
|
|
345
359
|
edge_ids_1,
|
|
346
360
|
field.tri_to_field,
|
|
@@ -351,20 +365,26 @@ class Assembler:
|
|
|
351
365
|
phi)
|
|
352
366
|
remove.update(rows)
|
|
353
367
|
Pmats.append(Pmat)
|
|
354
|
-
|
|
368
|
+
|
|
355
369
|
if Pmats:
|
|
370
|
+
logger.trace(f'.periodic bc removes {len(remove)} boundary DoF')
|
|
356
371
|
Pmat = Pmats[0]
|
|
357
372
|
for P2 in Pmats[1:]:
|
|
358
373
|
Pmat = Pmat @ P2
|
|
359
|
-
|
|
374
|
+
remove_array = np.sort(np.unique(list(remove)))
|
|
360
375
|
all_indices = np.arange(NF)
|
|
361
|
-
keep_indices = np.setdiff1d(all_indices,
|
|
376
|
+
keep_indices = np.setdiff1d(all_indices, remove_array)
|
|
362
377
|
Pmat = Pmat[:,keep_indices]
|
|
363
378
|
else:
|
|
364
379
|
Pmat = None
|
|
365
380
|
|
|
366
|
-
|
|
367
|
-
|
|
381
|
+
|
|
382
|
+
############################################################
|
|
383
|
+
# FINALIZE #
|
|
384
|
+
############################################################
|
|
385
|
+
|
|
386
|
+
pec_ids_set = set(pec_ids)
|
|
387
|
+
solve_ids = np.array([i for i in range(E.shape[0]) if i not in pec_ids_set])
|
|
368
388
|
|
|
369
389
|
if has_periodic:
|
|
370
390
|
mask = np.zeros((NF,))
|
|
@@ -419,20 +439,20 @@ class Assembler:
|
|
|
419
439
|
|
|
420
440
|
er = er - 1j*sig/(w0*EPS0)*np.repeat(np.eye(3)[:, :, np.newaxis], er.shape[2], axis=2)
|
|
421
441
|
|
|
422
|
-
logger.debug('
|
|
442
|
+
logger.debug('Assembling matrices')
|
|
423
443
|
E, B = tet_mass_stiffness_matrices(field, er, ur)
|
|
424
444
|
self.cached_matrices = (E, B)
|
|
425
445
|
|
|
426
446
|
NF = E.shape[0]
|
|
427
447
|
|
|
428
448
|
pecs: list[PEC] = [bc for bc in bcs if isinstance(bc,PEC)]
|
|
429
|
-
robin_bcs: list[RectangularWaveguide] = [bc for bc in bcs if isinstance(bc,RobinBC)]
|
|
449
|
+
robin_bcs: list[RectangularWaveguide] = [bc for bc in bcs if isinstance(bc,RobinBC)] # type: ignore
|
|
430
450
|
periodic: list[Periodic] = [bc for bc in bcs if isinstance(bc, Periodic)]
|
|
431
451
|
|
|
432
452
|
# Process all PEC Boundary Conditions
|
|
433
|
-
pec_ids = []
|
|
453
|
+
pec_ids: list = []
|
|
434
454
|
|
|
435
|
-
logger.debug('
|
|
455
|
+
logger.debug('Implementing PEC Boundary Conditions.')
|
|
436
456
|
|
|
437
457
|
# Conductivity above a limit, consider it all PEC
|
|
438
458
|
for itet in range(field.n_tets):
|
|
@@ -457,45 +477,52 @@ class Assembler:
|
|
|
457
477
|
|
|
458
478
|
# Robin BCs
|
|
459
479
|
if len(robin_bcs) > 0:
|
|
460
|
-
logger.debug('
|
|
480
|
+
logger.debug('Implementing Robin Boundary Conditions.')
|
|
481
|
+
|
|
482
|
+
if len(robin_bcs) > 0:
|
|
483
|
+
logger.debug('Implementing Robin Boundary Conditions.')
|
|
461
484
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
ibasis =
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
485
|
+
gauss_points = gaus_quad_tri(4)
|
|
486
|
+
Bempty = field.empty_tri_matrix()
|
|
487
|
+
for bc in robin_bcs:
|
|
488
|
+
|
|
489
|
+
for tag in bc.tags:
|
|
490
|
+
face_tags = [tag,]
|
|
491
|
+
|
|
492
|
+
tri_ids = mesh.get_triangles(face_tags)
|
|
493
|
+
nodes = mesh.get_nodes(face_tags)
|
|
494
|
+
edge_ids = list(mesh.tri_to_edge[:,tri_ids].flatten())
|
|
495
|
+
|
|
496
|
+
gamma = bc.get_gamma(k0)
|
|
497
|
+
|
|
498
|
+
ibasis = bc.get_inv_basis()
|
|
499
|
+
if ibasis is None:
|
|
500
|
+
basis = plane_basis_from_points(mesh.nodes[:,nodes]) + 1e-16
|
|
501
|
+
ibasis = np.linalg.pinv(basis)
|
|
502
|
+
|
|
503
|
+
Bempty = assemble_robin_bc(field, Bempty, tri_ids, gamma) # type: ignore
|
|
504
|
+
B_p = field.generate_csr(Bempty)
|
|
505
|
+
B = B + B_p
|
|
479
506
|
|
|
480
507
|
if len(periodic) > 0:
|
|
481
|
-
logger.debug('
|
|
508
|
+
logger.debug('Implementing Periodic Boundary Conditions.')
|
|
482
509
|
|
|
483
510
|
# Periodic BCs
|
|
484
511
|
Pmats = []
|
|
485
512
|
remove = set()
|
|
486
513
|
has_periodic = False
|
|
487
514
|
|
|
488
|
-
for
|
|
515
|
+
for bcp in periodic:
|
|
489
516
|
has_periodic = True
|
|
490
|
-
tri_ids_1 = mesh.get_triangles(
|
|
491
|
-
edge_ids_1 = mesh.get_edges(
|
|
492
|
-
tri_ids_2 = mesh.get_triangles(
|
|
493
|
-
edge_ids_2 = mesh.get_edges(
|
|
494
|
-
dv = np.array(
|
|
517
|
+
tri_ids_1 = mesh.get_triangles(bcp.face1.tags)
|
|
518
|
+
edge_ids_1 = mesh.get_edges(bcp.face1.tags)
|
|
519
|
+
tri_ids_2 = mesh.get_triangles(bcp.face2.tags)
|
|
520
|
+
edge_ids_2 = mesh.get_edges(bcp.face2.tags)
|
|
521
|
+
dv = np.array(bcp.dv)
|
|
495
522
|
linked_tris = pair_coordinates(mesh.tri_centers, tri_ids_1, tri_ids_2, dv, 1e-9)
|
|
496
523
|
linked_edges = pair_coordinates(mesh.edge_centers, edge_ids_1, edge_ids_2, dv, 1e-9)
|
|
497
|
-
dv = np.array(
|
|
498
|
-
phi =
|
|
524
|
+
dv = np.array(bcp.dv)
|
|
525
|
+
phi = bcp.phi(k0)
|
|
499
526
|
|
|
500
527
|
Pmat, rows = gen_periodic_matrix(tri_ids_1,
|
|
501
528
|
edge_ids_1,
|
|
@@ -513,15 +540,15 @@ class Assembler:
|
|
|
513
540
|
for P2 in Pmats[1:]:
|
|
514
541
|
Pmat = Pmat @ P2
|
|
515
542
|
Pmat = Pmat.tocsr()
|
|
516
|
-
|
|
543
|
+
remove_array = np.sort(np.array(list(remove)))
|
|
517
544
|
all_indices = np.arange(NF)
|
|
518
|
-
keep_indices = np.setdiff1d(all_indices,
|
|
545
|
+
keep_indices = np.setdiff1d(all_indices, remove_array)
|
|
519
546
|
Pmat = Pmat[:,keep_indices]
|
|
520
547
|
else:
|
|
521
548
|
Pmat = None
|
|
522
549
|
|
|
523
|
-
|
|
524
|
-
solve_ids = np.array([i for i in range(E.shape[0]) if i not in
|
|
550
|
+
pec_ids_set = set(pec_ids)
|
|
551
|
+
solve_ids = np.array([i for i in range(E.shape[0]) if i not in pec_ids_set])
|
|
525
552
|
|
|
526
553
|
if has_periodic:
|
|
527
554
|
mask = np.zeros((NF,))
|
|
@@ -22,16 +22,12 @@ from numba_progress import ProgressBar, ProgressBarType
|
|
|
22
22
|
from ....mth.optimized import local_mapping, matinv, dot_c, cross_c, compute_distances
|
|
23
23
|
from numba import c16, types, f8, i8, njit, prange
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
############################################################
|
|
27
26
|
# CACHED FACTORIAL VALUES #
|
|
28
27
|
############################################################
|
|
29
28
|
|
|
30
|
-
|
|
31
29
|
_FACTORIALS = np.array([1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880], dtype=np.int64)
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
31
|
############################################################
|
|
36
32
|
# INDEX MAPPING FUNCTIONS #
|
|
37
33
|
############################################################
|
|
@@ -264,7 +260,6 @@ def ned2_tet_stiff_mass(tet_vertices, edge_lengths, local_edge_map, local_tri_ma
|
|
|
264
260
|
Dmat[ei+0,ej+10] = Q*VAD
|
|
265
261
|
Dmat[ei+10,ej+0] = Q*VBC
|
|
266
262
|
Dmat[ei+10,ej+10] = Q*VBD
|
|
267
|
-
|
|
268
263
|
|
|
269
264
|
Fmat[ei+0,ej+0] = Q2*(VABCD*BD1-VABCC*BE1-VAACD*BF1+VAACC*BG1)
|
|
270
265
|
Fmat[ei+0,ej+10] = Q2*(VABDD*BD1-VABCD*BE1-VAADD*BF1+VAACD*BG1)
|
|
@@ -313,7 +308,6 @@ def ned2_tet_stiff_mass(tet_vertices, edge_lengths, local_edge_map, local_tri_ma
|
|
|
313
308
|
BH1 = dot_c(GB,BC1)
|
|
314
309
|
BI1 = dot_c(GA,BD1)
|
|
315
310
|
BJ1 = dot_c(GB,BD1)
|
|
316
|
-
|
|
317
311
|
|
|
318
312
|
Dmat[ei+0,ej+6] = L1*Lac2*(-6*VAD*AI1-3*VAC*AJ1-3*VAF*AK1)
|
|
319
313
|
Dmat[ei+0,ej+16] = L1*Lab2*(6*VAF*AK1+3*VAD*AI1-3*VAC*AJ1)
|
|
@@ -372,7 +366,6 @@ def ned2_tet_stiff_mass(tet_vertices, edge_lengths, local_edge_map, local_tri_ma
|
|
|
372
366
|
VBCEF = VOLUME_COEFF_CACHE[B,E,F,C]
|
|
373
367
|
VADEF = VOLUME_COEFF_CACHE[E,A,D,F]
|
|
374
368
|
|
|
375
|
-
|
|
376
369
|
Lac2 = Ds[ej1, fj]
|
|
377
370
|
Lab2 = Ds[ej1, ej2]
|
|
378
371
|
|
|
@@ -447,7 +440,7 @@ def _matrix_builder(nodes, tets, tris, edges, all_edge_lengths, tet_to_field, te
|
|
|
447
440
|
dataB = np.empty_like(rows, dtype=np.complex128)
|
|
448
441
|
|
|
449
442
|
|
|
450
|
-
for itet in prange(nT):
|
|
443
|
+
for itet in prange(nT): # ty: ignore
|
|
451
444
|
p = itet*400
|
|
452
445
|
if np.mod(itet,10)==0:
|
|
453
446
|
pgb.update(10)
|
|
@@ -17,21 +17,33 @@
|
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
19
|
from ....elements.nedleg2 import NedelecLegrange2
|
|
20
|
-
from scipy.sparse import
|
|
20
|
+
from scipy.sparse import csr_matrix
|
|
21
21
|
from numba_progress import ProgressBar, ProgressBarType
|
|
22
22
|
from ....mth.optimized import local_mapping, matinv, compute_distances
|
|
23
23
|
from numba import c16, types, f8, i8, njit, prange
|
|
24
24
|
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
############################################################
|
|
28
|
+
# FIELD MAPPING #
|
|
29
|
+
############################################################
|
|
30
|
+
|
|
25
31
|
@njit(i8[:,:](i8, i8[:,:], i8[:,:], i8[:,:]), cache=True, nogil=True)
|
|
26
32
|
def local_tri_to_edgeid(itri: int, tris, edges, tri_to_edge) -> np.ndarray:
|
|
27
33
|
global_edge_map = edges[:, tri_to_edge[:,itri]]
|
|
28
34
|
return local_mapping(tris[:, itri], global_edge_map)
|
|
29
35
|
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
############################################################
|
|
39
|
+
# PYTHON INTERFACE #
|
|
40
|
+
############################################################
|
|
41
|
+
|
|
30
42
|
def generelized_eigenvalue_matrix(field: NedelecLegrange2,
|
|
31
43
|
er: np.ndarray,
|
|
32
44
|
ur: np.ndarray,
|
|
33
45
|
basis: np.ndarray,
|
|
34
|
-
k0: float,) -> tuple[
|
|
46
|
+
k0: float,) -> tuple[csr_matrix, csr_matrix]:
|
|
35
47
|
|
|
36
48
|
tris = field.mesh.tris
|
|
37
49
|
edges = field.mesh.edges
|
|
@@ -47,11 +59,16 @@ def generelized_eigenvalue_matrix(field: NedelecLegrange2,
|
|
|
47
59
|
|
|
48
60
|
nfield = field.n_field
|
|
49
61
|
|
|
50
|
-
E =
|
|
51
|
-
B =
|
|
62
|
+
E = csr_matrix((dataE, (rows, cols)), shape=(nfield, nfield))
|
|
63
|
+
B = csr_matrix((dataB, (rows, cols)), shape=(nfield, nfield))
|
|
52
64
|
|
|
53
65
|
return E, B
|
|
54
66
|
|
|
67
|
+
|
|
68
|
+
############################################################
|
|
69
|
+
# MATRIX MULTIPLICATION #
|
|
70
|
+
############################################################
|
|
71
|
+
|
|
55
72
|
@njit(c16[:,:](c16[:,:], c16[:,:]), cache=True, nogil=True)
|
|
56
73
|
def matmul(a, b):
|
|
57
74
|
out = np.empty((2,b.shape[1]), dtype=np.complex128)
|
|
@@ -59,7 +76,10 @@ def matmul(a, b):
|
|
|
59
76
|
out[1,:] = a[1,0]*b[0,:] + a[1,1]*b[1,:]
|
|
60
77
|
return out
|
|
61
78
|
|
|
62
|
-
|
|
79
|
+
|
|
80
|
+
############################################################
|
|
81
|
+
# GAUSS QUADRATURE IMPLEMENTATION #
|
|
82
|
+
############################################################
|
|
63
83
|
|
|
64
84
|
@njit(c16(c16[:], c16[:], types.Array(types.float64, 1, 'A', readonly=True)), cache=True, nogil=True)
|
|
65
85
|
def _gqi(v1, v2, W):
|
|
@@ -185,7 +205,12 @@ def _nf2_curl(coeff, coords):
|
|
|
185
205
|
ys = coords[1,:]
|
|
186
206
|
return 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) + 0*1j
|
|
187
207
|
|
|
188
|
-
|
|
208
|
+
|
|
209
|
+
############################################################
|
|
210
|
+
# TRIANGLE BARYCENTRIC COORDINATE LIN. COEFFICIENTS #
|
|
211
|
+
############################################################
|
|
212
|
+
|
|
213
|
+
|
|
189
214
|
@njit(types.Tuple((f8[:], f8[:], f8[:], f8))(f8[:], f8[:]), cache = True, nogil=True)
|
|
190
215
|
def tri_coefficients(vxs, vys):
|
|
191
216
|
|
|
@@ -211,13 +236,23 @@ def tri_coefficients(vxs, vys):
|
|
|
211
236
|
Cs = np.array([c1, c2, c3])*sign
|
|
212
237
|
return As, Bs, Cs, A
|
|
213
238
|
|
|
214
|
-
|
|
239
|
+
|
|
240
|
+
############################################################
|
|
241
|
+
# CONSTANT DEFINITION #
|
|
242
|
+
############################################################
|
|
243
|
+
|
|
215
244
|
|
|
216
245
|
DPTS = np.array([[0.22338159, 0.22338159, 0.22338159, 0.10995174, 0.10995174, 0.10995174],
|
|
217
246
|
[0.10810302, 0.44594849, 0.44594849, 0.81684757, 0.09157621, 0.09157621],
|
|
218
247
|
[0.44594849, 0.44594849, 0.10810302, 0.09157621, 0.09157621, 0.81684757],
|
|
219
248
|
[0.44594849, 0.10810302, 0.44594849, 0.09157621, 0.81684757, 0.09157621]], dtype=np.float64)
|
|
220
249
|
|
|
250
|
+
|
|
251
|
+
############################################################
|
|
252
|
+
# NUMBA OPTIMIZED ASSEMBLER #
|
|
253
|
+
############################################################
|
|
254
|
+
|
|
255
|
+
|
|
221
256
|
@njit(types.Tuple((c16[:,:], c16[:,:]))(f8[:,:], i8[:,:], c16[:,:], c16[:,:], f8), cache=True, nogil=True)
|
|
222
257
|
def generalized_matrix_GQ(tri_vertices, local_edge_map, Ms, Mm, k0):
|
|
223
258
|
'''Nedelec-2 Triangle stiffness and mass submatrix'''
|
|
@@ -402,7 +437,7 @@ def _matrix_builder(nodes, tris, edges, tri_to_field, ur, er, k0, pgb: ProgressB
|
|
|
402
437
|
|
|
403
438
|
tri_to_edge = tri_to_field[:3,:]
|
|
404
439
|
|
|
405
|
-
for itri in prange(ntritot):
|
|
440
|
+
for itri in prange(ntritot): # type: ignore
|
|
406
441
|
p = itri*196
|
|
407
442
|
if np.mod(itri,10)==0:
|
|
408
443
|
pgb.update(10)
|
|
@@ -252,7 +252,7 @@ def ned2_tri_stiff_force(lcs_vertices, gamma, lcs_Uinc, DPTs):
|
|
|
252
252
|
def compute_bc_entries_excited(vertices_local, tris, Bmat, Bvec, surf_triangle_indices, gamma, Ulocal_all, DPTs, tri_to_field):
|
|
253
253
|
N = 64
|
|
254
254
|
Niter = surf_triangle_indices.shape[0]
|
|
255
|
-
for i in prange(Niter):
|
|
255
|
+
for i in prange(Niter): # type: ignore
|
|
256
256
|
itri = surf_triangle_indices[i]
|
|
257
257
|
|
|
258
258
|
vertex_ids = tris[:, itri]
|
|
@@ -388,7 +388,7 @@ def ned2_tri_stiff(vertices, edge_lengths, gamma):
|
|
|
388
388
|
def compute_bc_entries(vertices, tris, Bmat, all_edge_lengths, surf_triangle_indices, gamma):
|
|
389
389
|
N = 64
|
|
390
390
|
Niter = surf_triangle_indices.shape[0]
|
|
391
|
-
for i in prange(Niter):
|
|
391
|
+
for i in prange(Niter): # type: ignore
|
|
392
392
|
itri = surf_triangle_indices[i]
|
|
393
393
|
|
|
394
394
|
vertex_ids = tris[:, itri]
|
|
@@ -404,7 +404,7 @@ def assemble_robin_bc_excited(field: Nedelec2,
|
|
|
404
404
|
Bmat: np.ndarray,
|
|
405
405
|
surf_triangle_indices: np.ndarray,
|
|
406
406
|
Ufunc: Callable,
|
|
407
|
-
gamma:
|
|
407
|
+
gamma: complex,
|
|
408
408
|
local_basis: np.ndarray,
|
|
409
409
|
origin: np.ndarray,
|
|
410
410
|
DPTs: np.ndarray):
|
|
@@ -424,8 +424,8 @@ def assemble_robin_bc_excited(field: Nedelec2,
|
|
|
424
424
|
|
|
425
425
|
def assemble_robin_bc(field: Nedelec2,
|
|
426
426
|
Bmat: np.ndarray,
|
|
427
|
-
|
|
428
|
-
|
|
427
|
+
surf_triangle_indices: np.ndarray,
|
|
428
|
+
gamma: np.ndarray):
|
|
429
429
|
vertices = field.mesh.nodes
|
|
430
430
|
all_edge_lengths = field.mesh.edge_lengths[field.mesh.tri_to_edge]
|
|
431
431
|
Bmat = compute_bc_entries(vertices, field.mesh.tris, Bmat, all_edge_lengths, surf_triangle_indices, gamma)
|