emerge 0.4.7__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 (78) hide show
  1. emerge/__init__.py +14 -14
  2. emerge/_emerge/__init__.py +42 -0
  3. emerge/_emerge/bc.py +197 -0
  4. emerge/_emerge/coord.py +119 -0
  5. emerge/_emerge/cs.py +523 -0
  6. emerge/_emerge/dataset.py +36 -0
  7. emerge/_emerge/elements/__init__.py +19 -0
  8. emerge/_emerge/elements/femdata.py +212 -0
  9. emerge/_emerge/elements/index_interp.py +64 -0
  10. emerge/_emerge/elements/legrange2.py +172 -0
  11. emerge/_emerge/elements/ned2_interp.py +645 -0
  12. emerge/_emerge/elements/nedelec2.py +140 -0
  13. emerge/_emerge/elements/nedleg2.py +217 -0
  14. emerge/_emerge/geo/__init__.py +24 -0
  15. emerge/_emerge/geo/horn.py +107 -0
  16. emerge/_emerge/geo/modeler.py +449 -0
  17. emerge/_emerge/geo/operations.py +254 -0
  18. emerge/_emerge/geo/pcb.py +1244 -0
  19. emerge/_emerge/geo/pcb_tools/calculator.py +28 -0
  20. emerge/_emerge/geo/pcb_tools/macro.py +79 -0
  21. emerge/_emerge/geo/pmlbox.py +204 -0
  22. emerge/_emerge/geo/polybased.py +529 -0
  23. emerge/_emerge/geo/shapes.py +427 -0
  24. emerge/_emerge/geo/step.py +77 -0
  25. emerge/_emerge/geo2d.py +86 -0
  26. emerge/_emerge/geometry.py +510 -0
  27. emerge/_emerge/howto.py +214 -0
  28. emerge/_emerge/logsettings.py +5 -0
  29. emerge/_emerge/material.py +118 -0
  30. emerge/_emerge/mesh3d.py +730 -0
  31. emerge/_emerge/mesher.py +339 -0
  32. emerge/_emerge/mth/common_functions.py +33 -0
  33. emerge/_emerge/mth/integrals.py +71 -0
  34. emerge/_emerge/mth/optimized.py +357 -0
  35. emerge/_emerge/periodic.py +263 -0
  36. emerge/_emerge/physics/__init__.py +0 -0
  37. emerge/_emerge/physics/microwave/__init__.py +1 -0
  38. emerge/_emerge/physics/microwave/adaptive_freq.py +279 -0
  39. emerge/_emerge/physics/microwave/assembly/assembler.py +569 -0
  40. emerge/_emerge/physics/microwave/assembly/curlcurl.py +448 -0
  41. emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +426 -0
  42. emerge/_emerge/physics/microwave/assembly/robinbc.py +433 -0
  43. emerge/_emerge/physics/microwave/microwave_3d.py +1150 -0
  44. emerge/_emerge/physics/microwave/microwave_bc.py +915 -0
  45. emerge/_emerge/physics/microwave/microwave_data.py +1148 -0
  46. emerge/_emerge/physics/microwave/periodic.py +82 -0
  47. emerge/_emerge/physics/microwave/port_functions.py +53 -0
  48. emerge/_emerge/physics/microwave/sc.py +175 -0
  49. emerge/_emerge/physics/microwave/simjob.py +147 -0
  50. emerge/_emerge/physics/microwave/sparam.py +138 -0
  51. emerge/_emerge/physics/microwave/touchstone.py +140 -0
  52. emerge/_emerge/plot/__init__.py +0 -0
  53. emerge/_emerge/plot/display.py +394 -0
  54. emerge/_emerge/plot/grapher.py +93 -0
  55. emerge/_emerge/plot/matplotlib/mpldisplay.py +264 -0
  56. emerge/_emerge/plot/pyvista/__init__.py +1 -0
  57. emerge/_emerge/plot/pyvista/display.py +931 -0
  58. emerge/_emerge/plot/pyvista/display_settings.py +24 -0
  59. emerge/_emerge/plot/simple_plots.py +551 -0
  60. emerge/_emerge/plot.py +225 -0
  61. emerge/_emerge/projects/__init__.py +0 -0
  62. emerge/_emerge/projects/_gen_base.txt +32 -0
  63. emerge/_emerge/projects/_load_base.txt +24 -0
  64. emerge/_emerge/projects/generate_project.py +40 -0
  65. emerge/_emerge/selection.py +596 -0
  66. emerge/_emerge/simmodel.py +444 -0
  67. emerge/_emerge/simulation_data.py +411 -0
  68. emerge/_emerge/solver.py +993 -0
  69. emerge/_emerge/system.py +54 -0
  70. emerge/cli.py +19 -0
  71. emerge/lib.py +1 -1
  72. emerge/plot.py +1 -1
  73. {emerge-0.4.7.dist-info → emerge-0.4.8.dist-info}/METADATA +1 -1
  74. emerge-0.4.8.dist-info/RECORD +78 -0
  75. emerge-0.4.8.dist-info/entry_points.txt +2 -0
  76. emerge-0.4.7.dist-info/RECORD +0 -9
  77. emerge-0.4.7.dist-info/entry_points.txt +0 -2
  78. {emerge-0.4.7.dist-info → emerge-0.4.8.dist-info}/WHEEL +0 -0
@@ -0,0 +1,645 @@
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
+ from numba import njit, f8, c16, i8, types
18
+ import numpy as np
19
+ from ..mth.optimized import compute_distances
20
+
21
+ @njit(types.Tuple((f8[:], f8[:], f8[:], f8[:], f8))(f8[:], f8[:], f8[:]), cache = True, nogil=True)
22
+ def tet_coefficients(xs, ys, zs):
23
+ ## THIS FUNCTION WORKS
24
+ x1, x2, x3, x4 = xs
25
+ y1, y2, y3, y4 = ys
26
+ z1, z2, z3, z4 = zs
27
+
28
+ aas = np.empty((4,), dtype=np.float64)
29
+ bbs = np.empty((4,), dtype=np.float64)
30
+ ccs = np.empty((4,), dtype=np.float64)
31
+ dds = np.empty((4,), dtype=np.float64)
32
+
33
+ V = np.abs(-x1*y2*z3/6 + x1*y2*z4/6 + x1*y3*z2/6 - x1*y3*z4/6 - x1*y4*z2/6 + x1*y4*z3/6 + x2*y1*z3/6 - x2*y1*z4/6 - x2*y3*z1/6 + x2*y3*z4/6 + x2*y4*z1/6 - x2*y4*z3/6 - x3*y1*z2/6 + x3*y1*z4/6 + x3*y2*z1/6 - x3*y2*z4/6 - x3*y4*z1/6 + x3*y4*z2/6 + x4*y1*z2/6 - x4*y1*z3/6 - x4*y2*z1/6 + x4*y2*z3/6 + x4*y3*z1/6 - x4*y3*z2/6)
34
+
35
+ aas[0] = x2*y3*z4 - x2*y4*z3 - x3*y2*z4 + x3*y4*z2 + x4*y2*z3 - x4*y3*z2
36
+ aas[1] = -x1*y3*z4 + x1*y4*z3 + x3*y1*z4 - x3*y4*z1 - x4*y1*z3 + x4*y3*z1
37
+ aas[2] = x1*y2*z4 - x1*y4*z2 - x2*y1*z4 + x2*y4*z1 + x4*y1*z2 - x4*y2*z1
38
+ aas[3] = -x1*y2*z3 + x1*y3*z2 + x2*y1*z3 - x2*y3*z1 - x3*y1*z2 + x3*y2*z1
39
+ bbs[0] = -y2*z3 + y2*z4 + y3*z2 - y3*z4 - y4*z2 + y4*z3
40
+ bbs[1] = y1*z3 - y1*z4 - y3*z1 + y3*z4 + y4*z1 - y4*z3
41
+ bbs[2] = -y1*z2 + y1*z4 + y2*z1 - y2*z4 - y4*z1 + y4*z2
42
+ bbs[3] = y1*z2 - y1*z3 - y2*z1 + y2*z3 + y3*z1 - y3*z2
43
+ ccs[0] = x2*z3 - x2*z4 - x3*z2 + x3*z4 + x4*z2 - x4*z3
44
+ ccs[1] = -x1*z3 + x1*z4 + x3*z1 - x3*z4 - x4*z1 + x4*z3
45
+ ccs[2] = x1*z2 - x1*z4 - x2*z1 + x2*z4 + x4*z1 - x4*z2
46
+ ccs[3] = -x1*z2 + x1*z3 + x2*z1 - x2*z3 - x3*z1 + x3*z2
47
+ dds[0] = -x2*y3 + x2*y4 + x3*y2 - x3*y4 - x4*y2 + x4*y3
48
+ dds[1] = x1*y3 - x1*y4 - x3*y1 + x3*y4 + x4*y1 - x4*y3
49
+ dds[2] = -x1*y2 + x1*y4 + x2*y1 - x2*y4 - x4*y1 + x4*y2
50
+ dds[3] = x1*y2 - x1*y3 - x2*y1 + x2*y3 + x3*y1 - x3*y2
51
+
52
+ return aas, bbs, ccs, dds, V
53
+
54
+ @njit(types.Tuple((f8[:], f8[:], f8[:], f8))(f8[:], f8[:]), cache = True, nogil=True)
55
+ def tri_coefficients(vxs, vys):
56
+
57
+ x1, x2, x3 = vxs
58
+ y1, y2, y3 = vys
59
+
60
+ a1 = x2*y3-y2*x3
61
+ a2 = x3*y1-y3*x1
62
+ a3 = x1*y2-y1*x2
63
+ b1 = y2-y3
64
+ b2 = y3-y1
65
+ b3 = y1-y2
66
+ c1 = x3-x2
67
+ c2 = x1-x3
68
+ c3 = x2-x1
69
+
70
+ #A = 0.5*(b1*c2 - b2*c1)
71
+ sA = 0.5*(((x1-x3)*(y2-y1) - (x1-x2)*(y3-y1)))
72
+ sign = np.sign(sA)
73
+ A = np.abs(sA)
74
+ As = np.array([a1, a2, a3])*sign
75
+ Bs = np.array([b1, b2, b3])*sign
76
+ Cs = np.array([c1, c2, c3])*sign
77
+ return As, Bs, Cs, A
78
+
79
+ @njit(i8[:, :](i8[:], i8[:, :]), cache=True, nogil=True)
80
+ def local_mapping(vertex_ids, triangle_ids):
81
+ """
82
+ Parameters
83
+ ----------
84
+ vertex_ids : 1-D int64 array (length 4)
85
+ Global vertex 0.1005964238ers of one tetrahedron, in *its* order
86
+ (v0, v1, v2, v3).
87
+
88
+ triangle_ids : 2-D int64 array (nTri × 3)
89
+ Each row is a global-ID triple of one face that belongs to this tet.
90
+
91
+ Returns
92
+ -------
93
+ local_tris : 2-D int64 array (nTri × 3)
94
+ Same triangles, but every entry replaced by the local index
95
+ 0,1,2,3 that the vertex has inside this tetrahedron.
96
+ (Guaranteed to be ∈{0,1,2,3}; no -1 ever appears if the input
97
+ really belongs to the tet.)
98
+ """
99
+ ndim = triangle_ids.shape[0]
100
+ ntri = triangle_ids.shape[1]
101
+ out = np.zeros(triangle_ids.shape, dtype=np.int64)
102
+
103
+ for t in range(ntri): # each triangle
104
+ for j in range(ndim): # each vertex in that triangle
105
+ gid = triangle_ids[j, t] # global ID to look up
106
+
107
+ # linear search over the four tet vertices
108
+ for k in range(4):
109
+ if vertex_ids[k] == gid:
110
+ out[j, t] = k # store local index 0-3
111
+ break # stop the k-loop
112
+
113
+ return out
114
+
115
+ @njit(types.Tuple((c16[:], c16[:], c16[:]))(f8[:,:], c16[:], i8[:,:], i8[:,:], i8[:,:], f8[:,:], i8[:,:], i8[:]), cache=True, nogil=True)
116
+ def ned2_tet_interp(coords: np.ndarray,
117
+ solutions: np.ndarray,
118
+ tets: np.ndarray,
119
+ tris: np.ndarray,
120
+ edges: np.ndarray,
121
+ nodes: np.ndarray,
122
+ tet_to_field: np.ndarray,
123
+ tetids: np.ndarray):
124
+ ''' Nedelec 2 tetrahedral interpolation'''
125
+ # Solution has shape (nEdges, nsols)
126
+ nNodes = coords.shape[1]
127
+ nEdges = edges.shape[1]
128
+
129
+ xs = coords[0,:]
130
+ ys = coords[1,:]
131
+ zs = coords[2,:]
132
+
133
+ Ex = np.zeros((nNodes, ), dtype=np.complex128)
134
+ Ey = np.zeros((nNodes, ), dtype=np.complex128)
135
+ Ez = np.zeros((nNodes, ), dtype=np.complex128)
136
+
137
+ for i_iter in range(tetids.shape[0]):
138
+ itet = tetids[i_iter]
139
+
140
+ iv1, iv2, iv3, iv4 = tets[:, itet]
141
+
142
+ g_node_ids = tets[:, itet]
143
+ g_edge_ids = edges[:, tet_to_field[:6, itet]]
144
+ g_tri_ids = tris[:, tet_to_field[6:10, itet]-nEdges]
145
+
146
+ l_edge_ids = local_mapping(g_node_ids, g_edge_ids)
147
+ l_tri_ids = local_mapping(g_node_ids, g_tri_ids)
148
+
149
+ v1 = nodes[:,iv1]
150
+ v2 = nodes[:,iv2]
151
+ v3 = nodes[:,iv3]
152
+ v4 = nodes[:,iv4]
153
+
154
+ bv1 = v2 - v1
155
+ bv2 = v3 - v1
156
+ bv3 = v4 - v1
157
+
158
+ blocal = np.zeros((3,3))
159
+ blocal[:,0] = bv1
160
+ blocal[:,1] = bv2
161
+ blocal[:,2] = bv3
162
+ basis = np.linalg.pinv(blocal)
163
+
164
+ coords_offset = coords - v1[:,np.newaxis]
165
+ coords_local = (basis @ (coords_offset))
166
+
167
+ field_ids = tet_to_field[:, itet]
168
+ Etet = solutions[field_ids]
169
+
170
+ inside = ((coords_local[0,:] + coords_local[1,:] + coords_local[2,:]) <= 1.00000001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6) & (coords_local[2,:] >= -1e-6)
171
+
172
+ if inside.sum() == 0:
173
+ continue
174
+
175
+ ######### INSIDE THE TETRAHEDRON #########
176
+
177
+ x = xs[inside==1]
178
+ y = ys[inside==1]
179
+ z = zs[inside==1]
180
+
181
+ xvs = nodes[0, tets[:,itet]]
182
+ yvs = nodes[1, tets[:,itet]]
183
+ zvs = nodes[2, tets[:,itet]]
184
+
185
+ a_s, b_s, c_s, d_s, V = tet_coefficients(xvs, yvs, zvs)
186
+
187
+ Em1s = Etet[0:6]
188
+ Ef1s = Etet[6:10]
189
+ Em2s = Etet[10:16]
190
+ Ef2s = Etet[16:20]
191
+
192
+ Exl = np.zeros(x.shape, dtype=np.complex128)
193
+ Eyl = np.zeros(x.shape, dtype=np.complex128)
194
+ Ezl = np.zeros(x.shape, dtype=np.complex128)
195
+ for ie in range(6):
196
+ Em1, Em2 = Em1s[ie], Em2s[ie]
197
+ edgeids = l_edge_ids[:, ie]
198
+ a1, a2 = a_s[edgeids]
199
+ b1, b2 = b_s[edgeids]
200
+ c1, c2 = c_s[edgeids]
201
+ d1, d2 = d_s[edgeids]
202
+ x1, x2 = xvs[edgeids]
203
+ y1, y2 = yvs[edgeids]
204
+ z1, z2 = zvs[edgeids]
205
+
206
+ L = np.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)
207
+ ex = L*(Em1*(a1 + b1*x + c1*y + d1*z) + Em2*(a2 + b2*x + c2*y + d2*z))*(b1*(a2 + b2*x + c2*y + d2*z) - b2*(a1 + b1*x + c1*y + d1*z))/(216*V**3)
208
+ ey = L*(Em1*(a1 + b1*x + c1*y + d1*z) + Em2*(a2 + b2*x + c2*y + d2*z))*(c1*(a2 + b2*x + c2*y + d2*z) - c2*(a1 + b1*x + c1*y + d1*z))/(216*V**3)
209
+ ez = L*(Em1*(a1 + b1*x + c1*y + d1*z) + Em2*(a2 + b2*x + c2*y + d2*z))*(d1*(a2 + b2*x + c2*y + d2*z) - d2*(a1 + b1*x + c1*y + d1*z))/(216*V**3)
210
+
211
+ Exl += ex
212
+ Eyl += ey
213
+ Ezl += ez
214
+
215
+ for ie in range(4):
216
+ Em1, Em2 = Ef1s[ie], Ef2s[ie]
217
+ triids = l_tri_ids[:, ie]
218
+ a1, a2, a3 = a_s[triids]
219
+ b1, b2, b3 = b_s[triids]
220
+ c1, c2, c3 = c_s[triids]
221
+ d1, d2, d3 = d_s[triids]
222
+
223
+ x1, x2, x3 = xvs[l_tri_ids[:, ie]]
224
+ y1, y2, y3 = yvs[l_tri_ids[:, ie]]
225
+ z1, z2, z3 = zvs[l_tri_ids[:, ie]]
226
+
227
+ L1 = np.sqrt((x1-x3)**2 + (y1-y3)**2 + (z1-z3)**2)
228
+ L2 = np.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)
229
+
230
+ ex = (-Em1*L1*(b1*(a3 + b3*x + c3*y + d3*z) - b3*(a1 + b1*x + c1*y + d1*z))*(a2 + b2*x + c2*y + d2*z) + Em2*L2*(b1*(a2 + b2*x + c2*y + d2*z) - b2*(a1 + b1*x + c1*y + d1*z))*(a3 + b3*x + c3*y + d3*z))/(216*V**3)
231
+ ey = (-Em1*L1*(c1*(a3 + b3*x + c3*y + d3*z) - c3*(a1 + b1*x + c1*y + d1*z))*(a2 + b2*x + c2*y + d2*z) + Em2*L2*(c1*(a2 + b2*x + c2*y + d2*z) - c2*(a1 + b1*x + c1*y + d1*z))*(a3 + b3*x + c3*y + d3*z))/(216*V**3)
232
+ ez = (-Em1*L1*(d1*(a3 + b3*x + c3*y + d3*z) - d3*(a1 + b1*x + c1*y + d1*z))*(a2 + b2*x + c2*y + d2*z) + Em2*L2*(d1*(a2 + b2*x + c2*y + d2*z) - d2*(a1 + b1*x + c1*y + d1*z))*(a3 + b3*x + c3*y + d3*z))/(216*V**3)
233
+
234
+ Exl += ex
235
+ Eyl += ey
236
+ Ezl += ez
237
+
238
+ Ex[inside] = Exl
239
+ Ey[inside] = Eyl
240
+ Ez[inside] = Ezl
241
+ return Ex, Ey, Ez
242
+
243
+ @njit(types.Tuple((c16[:], c16[:], c16[:]))(f8[:,:], c16[:], i8[:,:], i8[:,:], i8[:,:], f8[:,:], i8[:,:], c16[:], i8[:]), cache=True, nogil=True)
244
+ def ned2_tet_interp_curl(coords: np.ndarray,
245
+ solutions: np.ndarray,
246
+ tets: np.ndarray,
247
+ tris: np.ndarray,
248
+ edges: np.ndarray,
249
+ nodes: np.ndarray,
250
+ tet_to_field: np.ndarray,
251
+ c: np.ndarray,
252
+ tetids: np.ndarray):
253
+ ''' Nedelec 2 tetrahedral interpolation of the analytic curl'''
254
+ # Solution has shape (nEdges, nsols)
255
+ nNodes = coords.shape[1]
256
+ nEdges = edges.shape[1]
257
+
258
+ xs = coords[0,:]
259
+ ys = coords[1,:]
260
+ zs = coords[2,:]
261
+
262
+ Ex = np.zeros((nNodes, ), dtype=np.complex128)
263
+ Ey = np.zeros((nNodes, ), dtype=np.complex128)
264
+ Ez = np.zeros((nNodes, ), dtype=np.complex128)
265
+
266
+ for i_iter in range(tetids.shape[0]):
267
+ itet = tetids[i_iter]
268
+
269
+ iv1, iv2, iv3, iv4 = tets[:, itet]
270
+
271
+ g_node_ids = tets[:, itet]
272
+ g_edge_ids = edges[:, tet_to_field[:6, itet]]
273
+ g_tri_ids = tris[:, tet_to_field[6:10, itet]-nEdges]
274
+
275
+ l_edge_ids = local_mapping(g_node_ids, g_edge_ids)
276
+ l_tri_ids = local_mapping(g_node_ids, g_tri_ids)
277
+
278
+ v1 = nodes[:,iv1]
279
+ v2 = nodes[:,iv2]
280
+ v3 = nodes[:,iv3]
281
+ v4 = nodes[:,iv4]
282
+
283
+ bv1 = v2 - v1
284
+ bv2 = v3 - v1
285
+ bv3 = v4 - v1
286
+
287
+ blocal = np.zeros((3,3))
288
+ blocal[:,0] = bv1
289
+ blocal[:,1] = bv2
290
+ blocal[:,2] = bv3
291
+ basis = np.linalg.pinv(blocal)
292
+
293
+ coords_offset = coords - v1[:,np.newaxis]
294
+ coords_local = (basis @ (coords_offset))
295
+
296
+ field_ids = tet_to_field[:, itet]
297
+ Etet = solutions[field_ids]
298
+
299
+ inside = ((coords_local[0,:] + coords_local[1,:] + coords_local[2,:]) <= 1.00000001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6) & (coords_local[2,:] >= -1e-6)
300
+
301
+ if inside.sum() == 0:
302
+ continue
303
+
304
+ const = c[itet]
305
+ ######### INSIDE THE TETRAHEDRON #########
306
+
307
+ x = xs[inside==1]
308
+ y = ys[inside==1]
309
+ z = zs[inside==1]
310
+
311
+ xvs = nodes[0, tets[:,itet]]
312
+ yvs = nodes[1, tets[:,itet]]
313
+ zvs = nodes[2, tets[:,itet]]
314
+
315
+ a_s, b_s, c_s, d_s, V = tet_coefficients(xvs, yvs, zvs)
316
+
317
+ Em1s = Etet[0:6]
318
+ Ef1s = Etet[6:10]
319
+ Em2s = Etet[10:16]
320
+ Ef2s = Etet[16:20]
321
+
322
+ Exl = np.zeros(x.shape, dtype=np.complex128)
323
+ Eyl = np.zeros(x.shape, dtype=np.complex128)
324
+ Ezl = np.zeros(x.shape, dtype=np.complex128)
325
+ for ie in range(6):
326
+ Em1, Em2 = Em1s[ie], Em2s[ie]
327
+ edgeids = l_edge_ids[:, ie]
328
+ a1, a2 = a_s[edgeids]
329
+ b1, b2 = b_s[edgeids]
330
+ c1, c2 = c_s[edgeids]
331
+ d1, d2 = d_s[edgeids]
332
+ x1, x2 = xvs[edgeids]
333
+ y1, y2 = yvs[edgeids]
334
+ z1, z2 = zvs[edgeids]
335
+
336
+ L = np.sqrt((x1 - x2)**2 + (y1 - y2)**2 + (z1 - z2)**2)
337
+ ex = L*(-Em1*a1*c1*d2 + Em1*a1*c2*d1 - Em1*b1*c1*d2*x + Em1*b1*c2*d1*x - Em1*c1**2*d2*y + Em1*c1*c2*d1*y - Em1*c1*d1*d2*z + Em1*c2*d1**2*z - Em2*a2*c1*d2 + Em2*a2*c2*d1 - Em2*b2*c1*d2*x + Em2*b2*c2*d1*x - Em2*c1*c2*d2*y - Em2*c1*d2**2*z + Em2*c2**2*d1*y + Em2*c2*d1*d2*z)/(72*V**3)
338
+ ey = L*(Em1*a1*b1*d2 - Em1*a1*b2*d1 + Em1*b1**2*d2*x - Em1*b1*b2*d1*x + Em1*b1*c1*d2*y + Em1*b1*d1*d2*z - Em1*b2*c1*d1*y - Em1*b2*d1**2*z + Em2*a2*b1*d2 - Em2*a2*b2*d1 + Em2*b1*b2*d2*x + Em2*b1*c2*d2*y + Em2*b1*d2**2*z - Em2*b2**2*d1*x - Em2*b2*c2*d1*y - Em2*b2*d1*d2*z)/(72*V**3)
339
+ ez = L*(-Em1*a1*b1*c2 + Em1*a1*b2*c1 - Em1*b1**2*c2*x + Em1*b1*b2*c1*x - Em1*b1*c1*c2*y - Em1*b1*c2*d1*z + Em1*b2*c1**2*y + Em1*b2*c1*d1*z - Em2*a2*b1*c2 + Em2*a2*b2*c1 - Em2*b1*b2*c2*x - Em2*b1*c2**2*y - Em2*b1*c2*d2*z + Em2*b2**2*c1*x + Em2*b2*c1*c2*y + Em2*b2*c1*d2*z)/(72*V**3)
340
+ Exl += ex
341
+ Eyl += ey
342
+ Ezl += ez
343
+
344
+ for ie in range(4):
345
+ Em1, Em2 = Ef1s[ie], Ef2s[ie]
346
+ triids = l_tri_ids[:, ie]
347
+ a1, a2, a3 = a_s[triids]
348
+ b1, b2, b3 = b_s[triids]
349
+ c1, c2, c3 = c_s[triids]
350
+ d1, d2, d3 = d_s[triids]
351
+
352
+ x1, x2, x3 = xvs[l_tri_ids[:, ie]]
353
+ y1, y2, y3 = yvs[l_tri_ids[:, ie]]
354
+ z1, z2, z3 = zvs[l_tri_ids[:, ie]]
355
+
356
+ L1 = np.sqrt((x1-x3)**2 + (y1-y3)**2 + (z1-z3)**2)
357
+ L2 = np.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)
358
+
359
+ ex = (Em1*L1*(-c2*(d1*(a3 + b3*x + c3*y + d3*z) - d3*(a1 + b1*x + c1*y + d1*z)) + d2*(c1*(a3 + b3*x + c3*y + d3*z) - c3*(a1 + b1*x + c1*y + d1*z)) + 2*(c1*d3 - c3*d1)*(a2 + b2*x + c2*y + d2*z)) - Em2*L2*(-c3*(d1*(a2 + b2*x + c2*y + d2*z) - d2*(a1 + b1*x + c1*y + d1*z)) + d3*(c1*(a2 + b2*x + c2*y + d2*z) - c2*(a1 + b1*x + c1*y + d1*z)) + 2*(c1*d2 - c2*d1)*(a3 + b3*x + c3*y + d3*z)))/(216*V**3)
360
+ ey = (-Em1*L1*(-b2*(d1*(a3 + b3*x + c3*y + d3*z) - d3*(a1 + b1*x + c1*y + d1*z)) + d2*(b1*(a3 + b3*x + c3*y + d3*z) - b3*(a1 + b1*x + c1*y + d1*z)) + 2*(b1*d3 - b3*d1)*(a2 + b2*x + c2*y + d2*z)) + Em2*L2*(-b3*(d1*(a2 + b2*x + c2*y + d2*z) - d2*(a1 + b1*x + c1*y + d1*z)) + d3*(b1*(a2 + b2*x + c2*y + d2*z) - b2*(a1 + b1*x + c1*y + d1*z)) + 2*(b1*d2 - b2*d1)*(a3 + b3*x + c3*y + d3*z)))/(216*V**3)
361
+ ez = (Em1*L1*(-b2*(c1*(a3 + b3*x + c3*y + d3*z) - c3*(a1 + b1*x + c1*y + d1*z)) + c2*(b1*(a3 + b3*x + c3*y + d3*z) - b3*(a1 + b1*x + c1*y + d1*z)) + 2*(b1*c3 - b3*c1)*(a2 + b2*x + c2*y + d2*z)) - Em2*L2*(-b3*(c1*(a2 + b2*x + c2*y + d2*z) - c2*(a1 + b1*x + c1*y + d1*z)) + c3*(b1*(a2 + b2*x + c2*y + d2*z) - b2*(a1 + b1*x + c1*y + d1*z)) + 2*(b1*c2 - b2*c1)*(a3 + b3*x + c3*y + d3*z)))/(216*V**3)
362
+
363
+ Exl += ex
364
+ Eyl += ey
365
+ Ezl += ez
366
+
367
+ Ex[inside] = Exl*const
368
+ Ey[inside] = Eyl*const
369
+ Ez[inside] = Ezl*const
370
+ return Ex, Ey, Ez
371
+
372
+ @njit(types.Tuple((c16[:], c16[:], c16[:]))(f8[:,:], c16[:], i8[:,:], f8[:,:], i8[:,:]), cache=True, nogil=True)
373
+ def ned2_tri_interp(coords: np.ndarray,
374
+ solutions: np.ndarray,
375
+ tris: np.ndarray,
376
+ nodes: np.ndarray,
377
+ tri_to_field: np.ndarray):
378
+ ''' Nedelec 2 tetrahedral interpolation'''
379
+ ### THIS IS VERIFIED TO WORK
380
+ # Solution has shape (nEdges, nsols)
381
+ nNodes = coords.shape[1]
382
+ xs = coords[0,:]
383
+ ys = coords[1,:]
384
+
385
+ Ex = np.zeros((nNodes, ), dtype=np.complex128)
386
+ Ey = np.zeros((nNodes, ), dtype=np.complex128)
387
+ Ez = np.zeros((nNodes, ), dtype=np.complex128)
388
+
389
+ nodes = nodes[:2,:]
390
+
391
+ l_edge_ids = np.array([[0,1,0],[1,2,2]])
392
+
393
+ for itri in range(tris.shape[1]):
394
+
395
+ iv1, iv2, iv3 = tris[:, itri]
396
+
397
+ v1 = nodes[:,iv1]
398
+ v2 = nodes[:,iv2]
399
+ v3 = nodes[:,iv3]
400
+
401
+ bv1 = v2 - v1
402
+ bv2 = v3 - v1
403
+
404
+ blocal = np.zeros((2,2))
405
+ blocal[:,0] = bv1
406
+ blocal[:,1] = bv2
407
+ basis = np.linalg.pinv(blocal)
408
+
409
+ coords_offset = coords - v1[:,np.newaxis]
410
+ coords_local = (basis @ (coords_offset))
411
+
412
+ field_ids = tri_to_field[:, itri]
413
+
414
+ Etri = solutions[field_ids]
415
+
416
+ inside = ((coords_local[0,:] + coords_local[1,:]) <= 1.0001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6)
417
+
418
+ if inside.sum() == 0:
419
+ continue
420
+
421
+ ######### INSIDE THE TETRAHEDRON #########
422
+
423
+ x = xs[inside==1]
424
+ y = ys[inside==1]
425
+
426
+ xvs = nodes[0, tris[:,itri]]
427
+ yvs = nodes[1, tris[:,itri]]
428
+
429
+ Ds = compute_distances(xvs, yvs, 0*xvs)
430
+
431
+ L1 = Ds[0,1]
432
+ L2 = Ds[1,2]
433
+ L3 = Ds[0,2]
434
+
435
+ mult = np.array([L1,L2,L3,L3,L1,L2,L3,L1])
436
+
437
+ a_s, b_s, c_s, A = tri_coefficients(xvs, yvs)
438
+
439
+ Etri = Etri*mult
440
+
441
+ Em1s = Etri[:3]
442
+ Ef1s = Etri[3]
443
+ Em2s = Etri[4:7]
444
+ Ef2s = Etri[7]
445
+
446
+ Exl = np.zeros(x.shape, dtype=np.complex128)
447
+ Eyl = np.zeros(x.shape, dtype=np.complex128)
448
+
449
+
450
+ for ie in range(3):
451
+ Em1, Em2 = Em1s[ie], Em2s[ie]
452
+ edgeids = l_edge_ids[:, ie]
453
+ a1, a2 = a_s[edgeids]
454
+ b1, b2 = b_s[edgeids]
455
+ c1, c2 = c_s[edgeids]
456
+
457
+ ex = (Em1*(a1 + b1*x + c1*y) + Em2*(a2 + b2*x + c2*y))*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))/(8*A**3)
458
+ ey = (Em1*(a1 + b1*x + c1*y) + Em2*(a2 + b2*x + c2*y))*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))/(8*A**3)
459
+
460
+ Exl += ex
461
+ Eyl += ey
462
+
463
+
464
+ Em1, Em2 = Ef1s, Ef2s
465
+ triids = np.array([0,1,2])
466
+
467
+ a1, a2, a3 = a_s[triids]
468
+ b1, b2, b3 = b_s[triids]
469
+ c1, c2, c3 = c_s[triids]
470
+
471
+ ex = (-Em1*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + Em2*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
472
+ ey = (-Em1*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + Em2*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
473
+
474
+ Exl += ex
475
+ Eyl += ey
476
+
477
+ Ex[inside] = Exl
478
+ Ey[inside] = Eyl
479
+ return Ex, Ey, Ez
480
+
481
+ @njit(types.Tuple((c16[:], c16[:], c16[:]))(f8[:,:], c16[:], i8[:,:], f8[:,:], i8[:,:]), cache=True, nogil=True)
482
+ def ned2_tri_interp_full(coords: np.ndarray,
483
+ solutions: np.ndarray,
484
+ tris: np.ndarray,
485
+ nodes: np.ndarray,
486
+ tri_to_field: np.ndarray):
487
+ ''' Nedelec 2 tetrahedral interpolation'''
488
+ ### THIS IS VERIFIED TO WORK
489
+ # Solution has shape (nEdges, nsols)
490
+ nNodes = coords.shape[1]
491
+ xs = coords[0,:]
492
+ ys = coords[1,:]
493
+
494
+ Ex = np.zeros((nNodes, ), dtype=np.complex128)
495
+ Ey = np.zeros((nNodes, ), dtype=np.complex128)
496
+ Ez = np.zeros((nNodes, ), dtype=np.complex128)
497
+
498
+ nodes = nodes[:2,:]
499
+
500
+ for itri in range(tris.shape[1]):
501
+
502
+ iv1, iv2, iv3 = tris[:, itri]
503
+
504
+ v1 = nodes[:,iv1]
505
+ v2 = nodes[:,iv2]
506
+ v3 = nodes[:,iv3]
507
+
508
+ bv1 = v2 - v1
509
+ bv2 = v3 - v1
510
+
511
+ blocal = np.zeros((2,2))
512
+ blocal[:,0] = bv1
513
+ blocal[:,1] = bv2
514
+ basis = np.linalg.pinv(blocal)
515
+
516
+ coords_offset = coords - v1[:,np.newaxis]
517
+ coords_local = (basis @ (coords_offset))
518
+
519
+ field_ids = tri_to_field[:, itri]
520
+
521
+ Etri = solutions[field_ids]
522
+
523
+ inside = ((coords_local[0,:] + coords_local[1,:]) <= 1.00001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6)
524
+
525
+ if inside.sum() == 0:
526
+ continue
527
+
528
+ ######### INSIDE THE TETRAHEDRON #########
529
+
530
+ x = xs[inside==1]
531
+ y = ys[inside==1]
532
+
533
+ xvs = nodes[0, tris[:,itri]]
534
+ yvs = nodes[1, tris[:,itri]]
535
+
536
+ Ds = compute_distances(xvs, yvs, 0*xvs)
537
+
538
+ L1 = Ds[0,1]
539
+ L2 = Ds[1,2]
540
+ L3 = Ds[0,2]
541
+
542
+ mult = np.array([L1,L2,L3,L3,L1,L2,L3,L1,1,1,1,1,1,1])
543
+
544
+ a_s, b_s, c_s, A = tri_coefficients(xvs, yvs)
545
+
546
+ e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri*mult
547
+
548
+ a1, a2, a3 = a_s
549
+ b1, b2, b3 = b_s
550
+ c1, c2, c3 = c_s
551
+
552
+ ex = (e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
553
+ ey = (e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y))/(8*A**3)
554
+ ez = (a1 + b1*x + c1*y)*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y))/(2*A**2)
555
+
556
+ Ex[inside] = ex
557
+ Ey[inside] = ey
558
+ Ez[inside] = ez
559
+ return Ex, Ey, Ez
560
+
561
+ @njit(types.Tuple((c16[:], c16[:], c16[:]))(f8[:,:], c16[:], i8[:,:], f8[:,:], i8[:,:], c16[:,:,:], c16), cache=True, nogil=True)
562
+ def ned2_tri_interp_curl(coords: np.ndarray,
563
+ solutions: np.ndarray,
564
+ tris: np.ndarray,
565
+ nodes: np.ndarray,
566
+ tri_to_field: np.ndarray,
567
+ diadic: np.ndarray,
568
+ beta: float):
569
+ ''' Nedelec 2 tetrahedral interpolation'''
570
+ ### THIS IS VERIFIED TO WORK
571
+ # Solution has shape (nEdges, nsols)
572
+ ### THIS IS VERIFIED TO WORK
573
+ # Solution has shape (nEdges, nsols)
574
+ nNodes = coords.shape[1]
575
+ xs = coords[0,:]
576
+ ys = coords[1,:]
577
+ jB = 1j*beta
578
+ Ex = np.zeros((nNodes, ), dtype=np.complex128)
579
+ Ey = np.zeros((nNodes, ), dtype=np.complex128)
580
+ Ez = np.zeros((nNodes, ), dtype=np.complex128)
581
+
582
+ nodes = nodes[:2,:]
583
+
584
+ for itri in range(tris.shape[1]):
585
+
586
+ dc = diadic[:,:,itri]
587
+
588
+ iv1, iv2, iv3 = tris[:, itri]
589
+
590
+ v1 = nodes[:,iv1]
591
+ v2 = nodes[:,iv2]
592
+ v3 = nodes[:,iv3]
593
+
594
+ bv1 = v2 - v1
595
+ bv2 = v3 - v1
596
+
597
+ blocal = np.zeros((2,2))
598
+ blocal[:,0] = bv1
599
+ blocal[:,1] = bv2
600
+ basis = np.linalg.pinv(blocal)
601
+
602
+ coords_offset = coords - v1[:,np.newaxis]
603
+ coords_local = (basis @ (coords_offset))
604
+
605
+ field_ids = tri_to_field[:, itri]
606
+
607
+ Etri = solutions[field_ids]
608
+
609
+ inside = ((coords_local[0,:] + coords_local[1,:]) <= 1.0001) & (coords_local[0,:] >= -1e-6) & (coords_local[1,:] >= -1e-6)
610
+
611
+ if inside.sum() == 0:
612
+ continue
613
+
614
+ ######### INSIDE THE TETRAHEDRON #########
615
+
616
+ x = xs[inside==1]
617
+ y = ys[inside==1]
618
+
619
+ xvs = nodes[0, tris[:,itri]]
620
+ yvs = nodes[1, tris[:,itri]]
621
+
622
+ a_s, b_s, c_s, A = tri_coefficients(xvs, yvs)
623
+
624
+ Ds = compute_distances(xvs, yvs, 0*xvs)
625
+
626
+ L1 = Ds[0,1]
627
+ L2 = Ds[1,2]
628
+ L3 = Ds[0,2]
629
+
630
+ mult = np.array([L1,L2,L3,L3,L1,L2,L3,L1,1,1,1,1,1,1])
631
+
632
+ e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14 = Etri*mult
633
+
634
+ a1, a2, a3 = a_s
635
+ b1, b2, b3 = b_s
636
+ c1, c2, c3 = c_s
637
+
638
+ hx = (4*A*(c1*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y)) + (a1 + b1*x + c1*y)*(c1*e10 + c1*e11 + c1*e9 + c2*e12 + c2*e13 + c2*e14)) + jB*(e1*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(c2*(a3 + b3*x + c3*y) - c3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(c1*(a3 + b3*x + c3*y) - c3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(c1*(a2 + b2*x + c2*y) - c2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y)))/(8*A**3)
639
+ hy = (4*A*(b1*(e10*(-A + a1 + b1*x + c1*y) + e11*(-A + a1 + b1*x + c1*y) + e12*(a2 + b2*x + c2*y) + e13*(a2 + b2*x + c2*y) + e14*(a2 + b2*x + c2*y) + e9*(-A + a1 + b1*x + c1*y)) + (a1 + b1*x + c1*y)*(b1*e10 + b1*e11 + b1*e9 + b2*e12 + b2*e13 + b2*e14)) - jB*(e1*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) + e2*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a2 + b2*x + c2*y) + e3*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a1 + b1*x + c1*y) - e4*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e5*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a2 + b2*x + c2*y) + e6*(b2*(a3 + b3*x + c3*y) - b3*(a2 + b2*x + c2*y))*(a3 + b3*x + c3*y) + e7*(b1*(a3 + b3*x + c3*y) - b3*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y) + e8*(b1*(a2 + b2*x + c2*y) - b2*(a1 + b1*x + c1*y))*(a3 + b3*x + c3*y)))/(8*A**3)
640
+ hz = (-3*a1*b1*c2*e1 - 3*a1*b1*c3*e3 + 3*a1*b2*c1*e1 + a1*b2*c3*e4 + a1*b2*c3*e8 + 3*a1*b3*c1*e3 - a1*b3*c2*e4 - a1*b3*c2*e8 - 3*a2*b1*c2*e5 + 2*a2*b1*c3*e4 - a2*b1*c3*e8 + 3*a2*b2*c1*e5 - 3*a2*b2*c3*e2 - 2*a2*b3*c1*e4 + a2*b3*c1*e8 + 3*a2*b3*c2*e2 + a3*b1*c2*e4 - 2*a3*b1*c2*e8 - 3*a3*b1*c3*e7 - a3*b2*c1*e4 + 2*a3*b2*c1*e8 - 3*a3*b2*c3*e6 + 3*a3*b3*c1*e7 + 3*a3*b3*c2*e6 - 3*b1**2*c2*e1*x - 3*b1**2*c3*e3*x + 3*b1*b2*c1*e1*x - 3*b1*b2*c2*e5*x + 3*b1*b2*c3*e4*x + 3*b1*b3*c1*e3*x - 3*b1*b3*c2*e8*x - 3*b1*b3*c3*e7*x - 3*b1*c1*c2*e1*y - 3*b1*c1*c3*e3*y - 3*b1*c2**2*e5*y + 3*b1*c2*c3*e4*y - 3*b1*c2*c3*e8*y - 3*b1*c3**2*e7*y + 3*b2**2*c1*e5*x - 3*b2**2*c3*e2*x - 3*b2*b3*c1*e4*x + 3*b2*b3*c1*e8*x + 3*b2*b3*c2*e2*x - 3*b2*b3*c3*e6*x + 3*b2*c1**2*e1*y + 3*b2*c1*c2*e5*y + 3*b2*c1*c3*e8*y - 3*b2*c2*c3*e2*y - 3*b2*c3**2*e6*y + 3*b3**2*c1*e7*x + 3*b3**2*c2*e6*x + 3*b3*c1**2*e3*y - 3*b3*c1*c2*e4*y + 3*b3*c1*c3*e7*y + 3*b3*c2**2*e2*y + 3*b3*c2*c3*e6*y)/(8*A**3)
641
+
642
+ Ex[inside] = hx*dc[0,0]
643
+ Ey[inside] = hy*dc[1,1]
644
+ Ez[inside] = hz*dc[2,2]
645
+ return Ex, Ey, Ez