emerge 0.4.6__py3-none-any.whl → 0.4.8__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.

Files changed (80) hide show
  1. emerge/__init__.py +54 -0
  2. emerge/__main__.py +5 -0
  3. emerge/_emerge/__init__.py +42 -0
  4. emerge/_emerge/bc.py +197 -0
  5. emerge/_emerge/coord.py +119 -0
  6. emerge/_emerge/cs.py +523 -0
  7. emerge/_emerge/dataset.py +36 -0
  8. emerge/_emerge/elements/__init__.py +19 -0
  9. emerge/_emerge/elements/femdata.py +212 -0
  10. emerge/_emerge/elements/index_interp.py +64 -0
  11. emerge/_emerge/elements/legrange2.py +172 -0
  12. emerge/_emerge/elements/ned2_interp.py +645 -0
  13. emerge/_emerge/elements/nedelec2.py +140 -0
  14. emerge/_emerge/elements/nedleg2.py +217 -0
  15. emerge/_emerge/geo/__init__.py +24 -0
  16. emerge/_emerge/geo/horn.py +107 -0
  17. emerge/_emerge/geo/modeler.py +449 -0
  18. emerge/_emerge/geo/operations.py +254 -0
  19. emerge/_emerge/geo/pcb.py +1244 -0
  20. emerge/_emerge/geo/pcb_tools/calculator.py +28 -0
  21. emerge/_emerge/geo/pcb_tools/macro.py +79 -0
  22. emerge/_emerge/geo/pmlbox.py +204 -0
  23. emerge/_emerge/geo/polybased.py +529 -0
  24. emerge/_emerge/geo/shapes.py +427 -0
  25. emerge/_emerge/geo/step.py +77 -0
  26. emerge/_emerge/geo2d.py +86 -0
  27. emerge/_emerge/geometry.py +510 -0
  28. emerge/_emerge/howto.py +214 -0
  29. emerge/_emerge/logsettings.py +5 -0
  30. emerge/_emerge/material.py +118 -0
  31. emerge/_emerge/mesh3d.py +730 -0
  32. emerge/_emerge/mesher.py +339 -0
  33. emerge/_emerge/mth/common_functions.py +33 -0
  34. emerge/_emerge/mth/integrals.py +71 -0
  35. emerge/_emerge/mth/optimized.py +357 -0
  36. emerge/_emerge/periodic.py +263 -0
  37. emerge/_emerge/physics/__init__.py +0 -0
  38. emerge/_emerge/physics/microwave/__init__.py +1 -0
  39. emerge/_emerge/physics/microwave/adaptive_freq.py +279 -0
  40. emerge/_emerge/physics/microwave/assembly/assembler.py +569 -0
  41. emerge/_emerge/physics/microwave/assembly/curlcurl.py +448 -0
  42. emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +426 -0
  43. emerge/_emerge/physics/microwave/assembly/robinbc.py +433 -0
  44. emerge/_emerge/physics/microwave/microwave_3d.py +1150 -0
  45. emerge/_emerge/physics/microwave/microwave_bc.py +915 -0
  46. emerge/_emerge/physics/microwave/microwave_data.py +1148 -0
  47. emerge/_emerge/physics/microwave/periodic.py +82 -0
  48. emerge/_emerge/physics/microwave/port_functions.py +53 -0
  49. emerge/_emerge/physics/microwave/sc.py +175 -0
  50. emerge/_emerge/physics/microwave/simjob.py +147 -0
  51. emerge/_emerge/physics/microwave/sparam.py +138 -0
  52. emerge/_emerge/physics/microwave/touchstone.py +140 -0
  53. emerge/_emerge/plot/__init__.py +0 -0
  54. emerge/_emerge/plot/display.py +394 -0
  55. emerge/_emerge/plot/grapher.py +93 -0
  56. emerge/_emerge/plot/matplotlib/mpldisplay.py +264 -0
  57. emerge/_emerge/plot/pyvista/__init__.py +1 -0
  58. emerge/_emerge/plot/pyvista/display.py +931 -0
  59. emerge/_emerge/plot/pyvista/display_settings.py +24 -0
  60. emerge/_emerge/plot/simple_plots.py +551 -0
  61. emerge/_emerge/plot.py +225 -0
  62. emerge/_emerge/projects/__init__.py +0 -0
  63. emerge/_emerge/projects/_gen_base.txt +32 -0
  64. emerge/_emerge/projects/_load_base.txt +24 -0
  65. emerge/_emerge/projects/generate_project.py +40 -0
  66. emerge/_emerge/selection.py +596 -0
  67. emerge/_emerge/simmodel.py +444 -0
  68. emerge/_emerge/simulation_data.py +411 -0
  69. emerge/_emerge/solver.py +993 -0
  70. emerge/_emerge/system.py +54 -0
  71. emerge/cli.py +19 -0
  72. emerge/lib.py +57 -0
  73. emerge/plot.py +1 -0
  74. emerge/pyvista.py +1 -0
  75. {emerge-0.4.6.dist-info → emerge-0.4.8.dist-info}/METADATA +1 -1
  76. emerge-0.4.8.dist-info/RECORD +78 -0
  77. emerge-0.4.8.dist-info/entry_points.txt +2 -0
  78. emerge-0.4.6.dist-info/RECORD +0 -4
  79. emerge-0.4.6.dist-info/entry_points.txt +0 -2
  80. {emerge-0.4.6.dist-info → emerge-0.4.8.dist-info}/WHEEL +0 -0
@@ -0,0 +1,433 @@
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 numba import njit, f8, c16, i8, types, prange
21
+ from ....elements import Nedelec2
22
+ from typing import Callable
23
+ from loguru import logger
24
+
25
+ _FACTORIALS = np.array([1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880], dtype=np.int64)
26
+
27
+ @njit(cache=True, fastmath=True, nogil=True)
28
+ def optim_matmul(B: np.ndarray, data: np.ndarray):
29
+ dnew = np.zeros_like(data)
30
+ dnew[0,:] = B[0,0]*data[0,:] + B[0,1]*data[1,:] + B[0,2]*data[2,:]
31
+ dnew[1,:] = B[1,0]*data[0,:] + B[1,1]*data[1,:] + B[1,2]*data[2,:]
32
+ dnew[2,:] = B[2,0]*data[0,:] + B[2,1]*data[1,:] + B[2,2]*data[2,:]
33
+ return dnew
34
+
35
+ @njit(f8(i8, i8, i8, i8), cache=True, fastmath=True, nogil=True)
36
+ def area_coeff(a, b, c, d):
37
+ klmn = np.array([0,0,0,0,0,0,0])
38
+ klmn[a] += 1
39
+ klmn[b] += 1
40
+ klmn[c] += 1
41
+ klmn[d] += 1
42
+ output = 2*(_FACTORIALS[klmn[1]]*_FACTORIALS[klmn[2]]*_FACTORIALS[klmn[3]]
43
+ *_FACTORIALS[klmn[4]]*_FACTORIALS[klmn[5]]*_FACTORIALS[klmn[6]])/_FACTORIALS[(np.sum(klmn[1:])+2)]
44
+ return output
45
+
46
+
47
+ NFILL = 5
48
+ AREA_COEFF_CACHE_BASE = np.zeros((NFILL,NFILL,NFILL,NFILL), dtype=np.float64)
49
+ for I in range(NFILL):
50
+ for J in range(NFILL):
51
+ for K in range(NFILL):
52
+ for L in range(NFILL):
53
+ AREA_COEFF_CACHE_BASE[I,J,K,L] = area_coeff(I,J,K,L)
54
+
55
+
56
+
57
+ @njit(f8(f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
58
+ def dot(a: np.ndarray, b: np.ndarray):
59
+ return a[0]*b[0] + a[1]*b[1]
60
+
61
+ @njit(f8[:](f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
62
+ def cross(a: np.ndarray, b: np.ndarray):
63
+ crossv = np.empty((3,), dtype=np.float64)
64
+ crossv[0] = a[1]*b[2] - a[2]*b[1]
65
+ crossv[1] = a[2]*b[0] - a[0]*b[2]
66
+ crossv[2] = a[0]*b[1] - a[1]*b[0]
67
+ return crossv
68
+
69
+ @njit(types.Tuple((f8[:],f8[:]))(f8[:,:], i8[:,:], f8[:,:], i8[:]), cache=True, nogil=True)
70
+ def generate_points(vertices_local, tris, DPTs, surf_triangle_indices):
71
+ NS = surf_triangle_indices.shape[0]
72
+ xall = np.zeros((DPTs.shape[1], NS))
73
+ yall = np.zeros((DPTs.shape[1], NS))
74
+
75
+ for i in range(NS):
76
+ itri = surf_triangle_indices[i]
77
+ vertex_ids = tris[:, itri]
78
+
79
+ x1, x2, x3 = vertices_local[0, vertex_ids]
80
+ y1, y2, y3 = vertices_local[1, vertex_ids]
81
+
82
+ xall[:,i] = x1*DPTs[1,:] + x2*DPTs[2,:] + x3*DPTs[3,:]
83
+ yall[:,i] = y1*DPTs[1,:] + y2*DPTs[2,:] + y3*DPTs[3,:]
84
+
85
+ xflat = xall.flatten()
86
+ yflat = yall.flatten()
87
+ return xflat, yflat
88
+
89
+ @njit(f8[:,:](f8[:], f8[:], f8[:]), cache=True, nogil=True, fastmath=True)
90
+ def compute_distances(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> np.ndarray:
91
+ N = xs.shape[0]
92
+ Ds = np.empty((N,N), dtype=np.float64)
93
+ for i in range(N):
94
+ for j in range(i,N):
95
+ Ds[i,j] = np.sqrt((xs[i]-xs[j])**2 + (ys[i]-ys[j])**2 + (zs[i]-zs[j])**2)
96
+ Ds[j,i] = Ds[i,j]
97
+ return Ds
98
+
99
+ @njit(types.Tuple((c16[:,:],c16[:]))(f8[:,:], c16, c16[:,:], f8[:,:]), cache=True, nogil=True, parallel=False)
100
+ def ned2_tri_stiff_force(lcs_vertices, gamma, lcs_Uinc, DPTs):
101
+ ''' Nedelec-2 Triangle Stiffness matrix and forcing vector (For Boundary Condition of the Third Kind)
102
+
103
+ '''
104
+ local_edge_map = np.array([[0,1,0],[1,2,2]])
105
+ Bmat = np.zeros((8,8), dtype=np.complex128)
106
+ bvec = np.zeros((8,), dtype=np.complex128)
107
+
108
+ xs = lcs_vertices[0,:]
109
+ ys = lcs_vertices[1,:]
110
+
111
+ x1, x2, x3 = xs
112
+ y1, y2, y3 = ys
113
+
114
+ a1 = x2*y3-y2*x3
115
+ a2 = x3*y1-y3*x1
116
+ a3 = x1*y2-y1*x2
117
+ b1 = y2-y3
118
+ b2 = y3-y1
119
+ b3 = y1-y2
120
+ c1 = x3-x2
121
+ c2 = x1-x3
122
+ c3 = x2-x1
123
+
124
+ As = np.array([a1, a2, a3])
125
+ Bs = np.array([b1, b2, b3])
126
+ Cs = np.array([c1, c2, c3])
127
+
128
+ Ds = compute_distances(xs, ys, np.zeros_like(xs))
129
+
130
+ GL1 = np.array([b1, c1])
131
+ GL2 = np.array([b2, c2])
132
+ GL3 = np.array([b3, c3])
133
+
134
+ GLs = (GL1, GL2, GL3)
135
+
136
+ Area = 0.5 * np.abs((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1))
137
+ signA = -np.sign((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1))
138
+
139
+ letters = [1,2,3,4,5,6]
140
+
141
+ tA, tB, tC = letters[0], letters[1], letters[2]
142
+ GtA, GtB, GtC = GLs[0], GLs[1], GLs[2]
143
+
144
+ Lt1, Lt2 = Ds[2, 0], Ds[1, 0]
145
+
146
+ Ux = lcs_Uinc[0,:]
147
+ Uy = lcs_Uinc[1,:]
148
+
149
+ x = x1*DPTs[1,:] + x2*DPTs[2,:] + x3*DPTs[3,:]
150
+ y = y1*DPTs[1,:] + y2*DPTs[2,:] + y3*DPTs[3,:]
151
+
152
+ Ws = DPTs[0,:]
153
+
154
+ COEFF = gamma/(2*Area)**2
155
+ AREA_COEFF = AREA_COEFF_CACHE_BASE * Area
156
+ for ei in range(3):
157
+ ei1, ei2 = local_edge_map[:, ei]
158
+ Li = Ds[ei1, ei2]
159
+
160
+ A = letters[ei1]
161
+ B = letters[ei2]
162
+
163
+ GA = GLs[ei1]
164
+ GB = GLs[ei2]
165
+
166
+ for ej in range(3):
167
+ ej1, ej2 = local_edge_map[:, ej]
168
+ Lj = Ds[ej1, ej2]
169
+
170
+ C = letters[ej1]
171
+ D = letters[ej2]
172
+
173
+ GC = GLs[ej1]
174
+ GD = GLs[ej2]
175
+
176
+ DAC = dot(GA,GC)
177
+ DAD = dot(GA,GD)
178
+ DBC = dot(GB,GC)
179
+ DBD = dot(GB,GD)
180
+ LL = Li*Lj
181
+
182
+ 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)
183
+ 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)
184
+ 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)
185
+ 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)
186
+
187
+ FA = dot(GA,GtC)
188
+ FB = dot(GA,GtA)
189
+ FC = dot(GB,GtC)
190
+ FD = dot(GB,GtA)
191
+ FE = dot(GA,GtB)
192
+ FF = dot(GB,GtB)
193
+
194
+ 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)
195
+ 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)
196
+ 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)
197
+ 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)
198
+ 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)
199
+ 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)
200
+ 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)
201
+ 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)
202
+
203
+ A1, A2 = As[ei1], As[ei2]
204
+ B1, B2 = Bs[ei1], Bs[ei2]
205
+ C1, C2 = Cs[ei1], Cs[ei2]
206
+
207
+ Q = A2 + B2*x + C2*y
208
+ Z = A1 + B1*x + C1*y
209
+ A4 = (4*Area**2)
210
+ Q2 = Q/A4
211
+ Z2 = Z/A4
212
+ Ar2 = 1/(2*Area)
213
+
214
+ Ee1x = (B1*Q2 - B2*Z2)*(Z)*Ar2
215
+ Ee1y = (C1*Q2 - C2*Z2)*(Z)*Ar2
216
+ Ee2x = (B1*Q2 - B2*Z2)*(Q)*Ar2
217
+ Ee2y = (C1*Q2 - C2*Z2)*(Q)*Ar2
218
+
219
+ bvec[ei] += signA*Area*Li*np.sum(Ws*(Ee1x*Ux + Ee1y*Uy))
220
+ bvec[ei+4] += signA*Area*Li*np.sum(Ws*(Ee2x*Ux + Ee2y*Uy))
221
+
222
+ H1 = dot(GtA,GtC)
223
+ H2 = dot(GtA,GtA)
224
+ H3 = dot(GtA,GtB)
225
+
226
+ Bmat[3,3] += Lt1*Lt1*(AREA_COEFF[tA,tB,tA,tB]*dot(GtC,GtC)-AREA_COEFF[tA,tB,tB,tC]*H1-AREA_COEFF[tB,tC,tA,tB]*H1+AREA_COEFF[tB,tC,tB,tC]*H2)
227
+ 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)
228
+ 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)
229
+ 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))
230
+
231
+ A1, A2, A3 = As
232
+ B1, B2, B3 = Bs
233
+ C1, C2, C3 = Cs
234
+
235
+ Q = A2 + B2*x + C2*y
236
+ Z = A1 + B1*x + C1*y
237
+ FA = (8*Area**3)
238
+ W = (A3 + B3*x + C3*y)/FA
239
+ W2 = Q*W
240
+
241
+ Ef1x = Lt1*(-B1*W2 + B3*(Z)*(Q)/FA)
242
+ Ef1y = Lt1*(-C1*W2 + C3*(Z)*(Q)/FA)
243
+ Ef2x = Lt2*(B1*W2 - B2*(Z)*W)
244
+ Ef2y = Lt2*(C1*W2 - C2*(Z)*W)
245
+
246
+ bvec[3] += signA*Area*np.sum(Ws*(Ef1x*Ux + Ef1y*Uy))
247
+ bvec[7] += signA*Area*np.sum(Ws*(Ef2x*Ux + Ef2y*Uy))
248
+ Bmat = Bmat * COEFF
249
+ return Bmat, bvec
250
+
251
+ @njit(types.Tuple((c16[:], c16[:]))(f8[:,:], i8[:,:], c16[:], c16[:], i8[:], c16, c16[:,:,:], f8[:,:], i8[:,:]), cache=True, nogil=True, parallel=False)
252
+ def compute_bc_entries_excited(vertices_local, tris, Bmat, Bvec, surf_triangle_indices, gamma, Ulocal_all, DPTs, tri_to_field):
253
+ N = 64
254
+ Niter = surf_triangle_indices.shape[0]
255
+ for i in prange(Niter):
256
+ itri = surf_triangle_indices[i]
257
+
258
+ vertex_ids = tris[:, itri]
259
+
260
+ Ulocal = Ulocal_all[:,:, i]
261
+
262
+ Bsub, bvec = ned2_tri_stiff_force(vertices_local[:,vertex_ids], gamma, Ulocal, DPTs)
263
+
264
+ indices = tri_to_field[:, itri]
265
+
266
+ Bmat[itri*N:(itri+1)*N] += Bsub.ravel()
267
+ Bvec[indices] += bvec
268
+ return Bmat, Bvec
269
+
270
+
271
+ @njit(c16[:,:](f8[:,:], f8[:], c16), cache=True, nogil=True, parallel=False)
272
+ def ned2_tri_stiff(vertices, edge_lengths, gamma):
273
+ ''' Nedelec-2 Triangle Stiffness matrix and forcing vector (For Boundary Condition of the Third Kind)
274
+
275
+ '''
276
+ local_edge_map = np.array([[0,1,0],[1,2,2]])
277
+ Bmat = np.zeros((8,8), dtype=np.complex128)
278
+
279
+ xs = vertices[0,:]
280
+ ys = vertices[1,:]
281
+ zs = vertices[2,:]
282
+
283
+ ax1 = np.array([xs[1]-xs[0], ys[1]-ys[0], zs[1]-zs[0]])
284
+ ax2 = np.array([xs[2]-xs[0], ys[2]-ys[0], zs[2]-zs[0]])
285
+ ax1 = ax1/np.linalg.norm(ax1)
286
+ ax2 = ax2/np.linalg.norm(ax2)
287
+
288
+ axn = cross(ax1, ax2)
289
+ ax2 = -cross(axn, ax1)
290
+ basis = np.zeros((3,3), dtype=np.float64)
291
+ basis[:,0] = ax1
292
+ basis[:,1] = ax2
293
+ basis[:,2] = axn
294
+ basis = np.linalg.pinv(basis)
295
+ lcs_vertices = basis @ np.ascontiguousarray(vertices)
296
+
297
+ xs = lcs_vertices[0,:]
298
+ ys = lcs_vertices[1,:]
299
+
300
+ x1, x2, x3 = xs
301
+ y1, y2, y3 = ys
302
+
303
+ b1 = y2-y3
304
+ b2 = y3-y1
305
+ b3 = y1-y2
306
+ c1 = x3-x2
307
+ c2 = x1-x3
308
+ c3 = x2-x1
309
+
310
+ Ds = compute_distances(xs, ys, np.zeros_like(xs))
311
+
312
+ GL1 = np.array([b1, c1])
313
+ GL2 = np.array([b2, c2])
314
+ GL3 = np.array([b3, c3])
315
+
316
+ GLs = (GL1, GL2, GL3)
317
+
318
+ Area = 0.5 * np.abs((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1))
319
+
320
+ letters = [1,2,3,4,5,6]
321
+
322
+ tA, tB, tC = letters[0], letters[1], letters[2]
323
+ GtA, GtB, GtC = GLs[0], GLs[1], GLs[2]
324
+
325
+ Lt1, Lt2 = Ds[2, 0], Ds[1, 0]
326
+
327
+ COEFF = gamma/(2*Area)**2
328
+ AREA_COEFF = AREA_COEFF_CACHE_BASE * Area
329
+ for ei in range(3):
330
+ ei1, ei2 = local_edge_map[:, ei]
331
+ Li = edge_lengths[ei]
332
+
333
+ A = letters[ei1]
334
+ B = letters[ei2]
335
+
336
+ GA = GLs[ei1]
337
+ GB = GLs[ei2]
338
+
339
+ for ej in range(3):
340
+ ej1, ej2 = local_edge_map[:, ej]
341
+ Lj = edge_lengths[ej]
342
+
343
+ C = letters[ej1]
344
+ D = letters[ej2]
345
+
346
+ GC = GLs[ej1]
347
+ GD = GLs[ej2]
348
+ DAC = dot(GA,GC)
349
+ DAD = dot(GA,GD)
350
+ DBC = dot(GB,GC)
351
+ DBD = dot(GB,GD)
352
+ LL = Li*Lj
353
+
354
+ Bmat[ei,ej] += LL*COEFF*(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)
355
+ Bmat[ei,ej+4] += LL*COEFF*(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)
356
+ Bmat[ei+4,ej] += LL*COEFF*(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)
357
+ Bmat[ei+4,ej+4] += LL*COEFF*(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)
358
+
359
+ FA = dot(GA,GtC)
360
+ FB = dot(GA,GtA)
361
+ FC = dot(GB,GtC)
362
+ FD = dot(GB,GtA)
363
+ FE = dot(GA,GtB)
364
+ FF = dot(GB,GtB)
365
+
366
+ Bmat[ei,3] += Li*Lt1*COEFF*(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)
367
+ Bmat[ei,7] += Li*Lt2*COEFF*(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)
368
+ Bmat[3,ei] += Lt1*Li*COEFF*(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)
369
+ Bmat[7,ei] += Lt2*Li*COEFF*(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)
370
+ Bmat[ei+4,3] += Li*Lt1*COEFF*(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)
371
+ Bmat[ei+4,7] += Li*Lt2*COEFF*(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)
372
+ Bmat[3,ei+4] += Lt1*Li*COEFF*(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)
373
+ Bmat[7,ei+4] += Lt2*Li*COEFF*(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)
374
+
375
+ H1 = dot(GtA,GtC)
376
+ H2 = dot(GtA,GtA)
377
+ H3 = dot(GtA,GtB)
378
+
379
+ Bmat[3,3] += Lt1*Lt1*(AREA_COEFF[tA,tB,tA,tB]*dot(GtC,GtC)-AREA_COEFF[tA,tB,tB,tC]*H1-AREA_COEFF[tB,tC,tA,tB]*H1+AREA_COEFF[tB,tC,tB,tC]*H2)
380
+ 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)
381
+ 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)
382
+ 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))
383
+
384
+
385
+ return Bmat
386
+
387
+ @njit(c16[:](f8[:,:], i8[:,:], c16[:], f8[:,:], i8[:], c16), cache=True, nogil=True, parallel=False)
388
+ def compute_bc_entries(vertices, tris, Bmat, all_edge_lengths, surf_triangle_indices, gamma):
389
+ N = 64
390
+ Niter = surf_triangle_indices.shape[0]
391
+ for i in prange(Niter):
392
+ itri = surf_triangle_indices[i]
393
+
394
+ vertex_ids = tris[:, itri]
395
+
396
+ edge_lengths = all_edge_lengths[:,itri]
397
+
398
+ Bsub = ned2_tri_stiff(vertices[:,vertex_ids], edge_lengths, gamma)
399
+
400
+ Bmat[itri*N:(itri+1)*N] = Bmat[itri*N:(itri+1)*N] + Bsub.ravel()
401
+ return Bmat
402
+
403
+ def assemble_robin_bc_excited(field: Nedelec2,
404
+ Bmat: np.ndarray,
405
+ surf_triangle_indices: np.ndarray,
406
+ Ufunc: Callable,
407
+ gamma: np.ndarray,
408
+ local_basis: np.ndarray,
409
+ origin: np.ndarray,
410
+ DPTs: np.ndarray):
411
+
412
+ Bvec = np.zeros((field.n_field,), dtype=np.complex128)
413
+
414
+ vertices_local = optim_matmul(local_basis, field.mesh.nodes - origin[:,np.newaxis])
415
+
416
+ xflat, yflat = generate_points(vertices_local, field.mesh.tris, DPTs, surf_triangle_indices)
417
+
418
+ Ulocal = Ufunc(xflat, yflat)
419
+
420
+ Ulocal_all = Ulocal.reshape((3, DPTs.shape[1], surf_triangle_indices.shape[0]))
421
+
422
+ Bmat, Bvec = compute_bc_entries_excited(vertices_local, field.mesh.tris, Bmat, Bvec, surf_triangle_indices, gamma, Ulocal_all, DPTs, field.tri_to_field)
423
+ return Bmat, Bvec
424
+
425
+ def assemble_robin_bc(field: Nedelec2,
426
+ Bmat: np.ndarray,
427
+ surf_triangle_indices: np.ndarray,
428
+ gamma: np.ndarray):
429
+ vertices = field.mesh.nodes
430
+ all_edge_lengths = field.mesh.edge_lengths[field.mesh.tri_to_edge]
431
+ Bmat = compute_bc_entries(vertices, field.mesh.tris, Bmat, all_edge_lengths, surf_triangle_indices, gamma)
432
+
433
+ return Bmat