emerge 0.4.11__py3-none-any.whl → 0.5.0__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 +15 -8
- emerge/_emerge/bc.py +41 -2
- emerge/_emerge/geo/__init__.py +1 -1
- emerge/_emerge/geo/pcb.py +49 -11
- emerge/_emerge/howto.py +2 -2
- emerge/_emerge/logsettings.py +83 -5
- emerge/_emerge/mesh3d.py +30 -12
- emerge/_emerge/mth/common_functions.py +28 -1
- emerge/_emerge/mth/integrals.py +25 -3
- emerge/_emerge/mth/optimized.py +126 -33
- emerge/_emerge/mth/pairing.py +97 -0
- emerge/_emerge/periodic.py +22 -0
- emerge/_emerge/physics/microwave/assembly/assembler.py +129 -155
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +35 -3
- emerge/_emerge/physics/microwave/assembly/periodicbc.py +130 -0
- emerge/_emerge/physics/microwave/microwave_3d.py +3 -3
- emerge/_emerge/physics/microwave/microwave_bc.py +5 -4
- emerge/_emerge/physics/microwave/microwave_data.py +2 -2
- emerge/_emerge/projects/_gen_base.txt +1 -1
- emerge/_emerge/simmodel.py +137 -126
- emerge/_emerge/solve_interfaces/pardiso_interface.py +468 -0
- emerge/_emerge/solver.py +102 -31
- emerge/lib.py +276 -41
- {emerge-0.4.11.dist-info → emerge-0.5.0.dist-info}/METADATA +1 -1
- {emerge-0.4.11.dist-info → emerge-0.5.0.dist-info}/RECORD +28 -26
- emerge/_emerge/pardiso/pardiso_solver.py +0 -455
- {emerge-0.4.11.dist-info → emerge-0.5.0.dist-info}/WHEEL +0 -0
- {emerge-0.4.11.dist-info → emerge-0.5.0.dist-info}/entry_points.txt +0 -0
- {emerge-0.4.11.dist-info → emerge-0.5.0.dist-info}/licenses/LICENSE +0 -0
emerge/_emerge/mth/optimized.py
CHANGED
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
from numba import njit, f8, i8, types, c16
|
|
19
19
|
import numpy as np
|
|
20
20
|
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
############################################################
|
|
24
|
+
# TRIANGLE GAUSS QUADRATURE POINTS #
|
|
25
|
+
############################################################
|
|
26
|
+
|
|
21
27
|
_GAUSQUADTRI = {
|
|
22
28
|
1: [(1, 1, 1/3, 1/3, 1/3),],
|
|
23
29
|
2: [(3, 1/3, 2/3, 1/6, 1/6),],
|
|
@@ -54,7 +60,9 @@ _GAUSQUADTRI = {
|
|
|
54
60
|
(6, 0.009421666963733, 0.009540815400299, 0.066803251012200, 0.923655933587500)]
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
############################################################
|
|
64
|
+
# TETRAHEDRON GAUSS QUADRATURE POINTS #
|
|
65
|
+
############################################################
|
|
58
66
|
|
|
59
67
|
_GAUSQUADTET = {
|
|
60
68
|
1: [(1, 1, 0.25, 0.25, 0.25, 0.25),],
|
|
@@ -69,9 +77,14 @@ _GAUSQUADTET = {
|
|
|
69
77
|
(1, 0.1493333333, 0.1005964238, 0.3994035762, 0.3994035762, 0.1005964238),
|
|
70
78
|
(1, 0.1493333333, 0.1005964238, 0.3994035762, 0.1005964238, 0.3994035762),
|
|
71
79
|
(1, 0.1493333333, 0.1005964238, 0.1005964238, 0.3994035762, 0.3994035762),],
|
|
72
|
-
5:
|
|
80
|
+
5: None
|
|
73
81
|
}
|
|
74
82
|
|
|
83
|
+
|
|
84
|
+
############################################################
|
|
85
|
+
# FUNCTIONS #
|
|
86
|
+
############################################################
|
|
87
|
+
|
|
75
88
|
def gaus_quad_tri(p: int) -> np.ndarray:
|
|
76
89
|
"""
|
|
77
90
|
Returns the duvanant quadrature triangle sample points W, L1, L2, L3, coordinates for a given order p.
|
|
@@ -135,6 +148,12 @@ def gaus_quad_tet(p: int) -> np.ndarray:
|
|
|
135
148
|
pts = np.array(Pts).T
|
|
136
149
|
return pts
|
|
137
150
|
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
############################################################
|
|
154
|
+
# NUMBA COMPILED #
|
|
155
|
+
############################################################
|
|
156
|
+
|
|
138
157
|
@njit(types.Tuple((f8[:], f8[:], f8[:], i8[:]))(f8[:,:], i8[:,:], f8[:,:]), cache=True, nogil=True)
|
|
139
158
|
def generate_int_points_tri(nodes: np.ndarray,
|
|
140
159
|
triangles: np.ndarray,
|
|
@@ -200,14 +219,44 @@ def generate_int_points_tet(nodes: np.ndarray,
|
|
|
200
219
|
shape = np.array((nPTS, tets.shape[1]))
|
|
201
220
|
|
|
202
221
|
return xall_flat, yall_flat, zall_flat, shape
|
|
203
|
-
############## 0.1005964238a Compiled
|
|
204
222
|
|
|
205
223
|
@njit(f8(f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
|
|
206
|
-
def dot(a: np.ndarray, b: np.ndarray):
|
|
224
|
+
def dot(a: np.ndarray, b: np.ndarray) -> float:
|
|
225
|
+
"""Computes a dot product of two 3D vectors
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
a (np.ndarray): (3,) array
|
|
229
|
+
b (np.ndarray): (3,) array
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
float: a · b
|
|
233
|
+
"""
|
|
234
|
+
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
|
|
235
|
+
|
|
236
|
+
@njit(c16(c16[:], c16[:]), cache=True, fastmath=True, nogil=True)
|
|
237
|
+
def dot_c(a: np.ndarray, b: np.ndarray) -> complex:
|
|
238
|
+
"""Computes the complex dot product of two 3D vectors
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
a (np.ndarray): (3,) array
|
|
242
|
+
b (np.ndarray): (3,) array
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
complex: a · b
|
|
246
|
+
"""
|
|
207
247
|
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
|
|
208
248
|
|
|
209
249
|
@njit(f8[:](f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
|
|
210
|
-
def cross(a: np.ndarray, b: np.ndarray):
|
|
250
|
+
def cross(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
251
|
+
"""Optimized single vector cross product
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
a (np.ndarray): (3,) vector a
|
|
255
|
+
b (np.ndarray): (3,) vector b
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
np.ndarray: a ⨉ b
|
|
259
|
+
"""
|
|
211
260
|
crossv = np.empty((3,), dtype=np.float64)
|
|
212
261
|
crossv[0] = a[1]*b[2] - a[2]*b[1]
|
|
213
262
|
crossv[1] = a[2]*b[0] - a[0]*b[2]
|
|
@@ -216,6 +265,15 @@ def cross(a: np.ndarray, b: np.ndarray):
|
|
|
216
265
|
|
|
217
266
|
@njit(c16[:](c16[:], c16[:]), cache=True, fastmath=True, nogil=True)
|
|
218
267
|
def cross_c(a: np.ndarray, b: np.ndarray):
|
|
268
|
+
"""Optimized complex single vector cross product
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
a (np.ndarray): (3,) vector a
|
|
272
|
+
b (np.ndarray): (3,) vector b
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
np.ndarray: a ⨉ b
|
|
276
|
+
"""
|
|
219
277
|
crossv = np.empty((3,), dtype=np.complex128)
|
|
220
278
|
crossv[0] = a[1]*b[2] - a[2]*b[1]
|
|
221
279
|
crossv[1] = a[2]*b[0] - a[0]*b[2]
|
|
@@ -223,7 +281,21 @@ def cross_c(a: np.ndarray, b: np.ndarray):
|
|
|
223
281
|
return crossv
|
|
224
282
|
|
|
225
283
|
@njit(f8[:](f8[:], f8[:], f8[:], f8[:]), cache=True, nogil=True)
|
|
226
|
-
def outward_normal(n1, n2, n3, o):
|
|
284
|
+
def outward_normal(n1: np.ndarray, n2: np.ndarray, n3: np.ndarray, o: np.ndarray) -> np.ndarray:
|
|
285
|
+
"""Copmutes an outward normal vector of a triangle spanned by 3 points.
|
|
286
|
+
|
|
287
|
+
Computes the triangle surface (n1, n2, n3) which have normal n.
|
|
288
|
+
The normal is aligned with respect to an origin.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
n1 (np.ndarray): Node 1 (3,) array
|
|
292
|
+
n2 (np.ndarray): Node 2 (3,) array
|
|
293
|
+
n3 (np.ndarray): Node 3 (3,) array
|
|
294
|
+
o (np.ndarray): The alignment origin
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
Node 1 (3,) array: The outward pointing normal
|
|
298
|
+
"""
|
|
227
299
|
e1 = n2-n1
|
|
228
300
|
e2 = n3-n1
|
|
229
301
|
n = cross(e1, e2)
|
|
@@ -234,16 +306,22 @@ def outward_normal(n1, n2, n3, o):
|
|
|
234
306
|
return n*sgn
|
|
235
307
|
|
|
236
308
|
@njit(f8(f8[:], f8[:], f8[:]), cache=True, fastmath=True, nogil=True)
|
|
237
|
-
def calc_area(x1: np.ndarray, x2: np.ndarray, x3: np.ndarray):
|
|
309
|
+
def calc_area(x1: np.ndarray, x2: np.ndarray, x3: np.ndarray) -> float:
|
|
310
|
+
"""Computes the tirangle surface area of the traingle spun by three nodes.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
x1 (np.ndarray): Node 1 (3,) array
|
|
314
|
+
x2 (np.ndarray): Node 2 (3,) array
|
|
315
|
+
x3 (np.ndarray): Node 3 (3,) array
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
float: The surface area
|
|
319
|
+
"""
|
|
238
320
|
e1 = x2 - x1
|
|
239
321
|
e2 = x3 - x1
|
|
240
322
|
av = cross(e1, e2)
|
|
241
323
|
return np.sqrt(av[0]**2 + av[1]**2 + av[2]**2)/2
|
|
242
324
|
|
|
243
|
-
@njit(c16(c16[:], c16[:]), cache=True, fastmath=True, nogil=True)
|
|
244
|
-
def dot_c(a: np.ndarray, b: np.ndarray):
|
|
245
|
-
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
|
|
246
|
-
|
|
247
325
|
@njit(i8[:, :](i8[:], i8[:, :]), cache=True, nogil=True)
|
|
248
326
|
def local_mapping(vertex_ids, triangle_ids):
|
|
249
327
|
"""
|
|
@@ -281,7 +359,7 @@ def local_mapping(vertex_ids, triangle_ids):
|
|
|
281
359
|
return out
|
|
282
360
|
|
|
283
361
|
@njit(f8[:,:](f8[:], f8[:], f8[:]), cache=True, nogil=True)
|
|
284
|
-
def orthonormal_basis(xs, ys, zs):
|
|
362
|
+
def orthonormal_basis(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray):
|
|
285
363
|
"""
|
|
286
364
|
Returns an orthonormal basis for the tetrahedron defined by the points
|
|
287
365
|
xs, ys, zs. The basis is given as a 3x3 matrix with the first column being
|
|
@@ -325,33 +403,48 @@ def compute_distances(xs: np.ndarray, ys: np.ndarray, zs: np.ndarray) -> np.ndar
|
|
|
325
403
|
ids = np.array([[0, 0, 1, 1, 2, 2],[1,2,0, 2, 0, 1]], dtype=np.int64)
|
|
326
404
|
|
|
327
405
|
@njit(c16[:,:](c16[:,:]), cache=True, nogil=True)
|
|
328
|
-
def matinv(
|
|
406
|
+
def matinv(M: np.ndarray) -> np.ndarray:
|
|
407
|
+
"""Optimized matrix inverse of 3x3 matrix
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
M (np.ndarray): Input matrix M of shape (3,3)
|
|
329
411
|
|
|
412
|
+
Returns:
|
|
413
|
+
np.ndarray: The matrix inverse inv(M)
|
|
414
|
+
"""
|
|
330
415
|
out = np.zeros((3,3), dtype=np.complex128)
|
|
331
416
|
|
|
332
|
-
if
|
|
333
|
-
out[0,0] = 1/
|
|
334
|
-
out[1,1] = 1/
|
|
335
|
-
out[2,2] = 1/
|
|
417
|
+
if M[0,1]==0 and M[0,2]==0 and M[1,0]==0 and M[1,2]==0 and M[2,0]==0 and M[2,1]==0:
|
|
418
|
+
out[0,0] = 1/M[0,0]
|
|
419
|
+
out[1,1] = 1/M[1,1]
|
|
420
|
+
out[2,2] = 1/M[2,2]
|
|
336
421
|
else:
|
|
337
|
-
det =
|
|
338
|
-
out[0,0] =
|
|
339
|
-
out[0,1] = -
|
|
340
|
-
out[0,2] =
|
|
341
|
-
out[1,0] = -
|
|
342
|
-
out[1,1] =
|
|
343
|
-
out[1,2] = -
|
|
344
|
-
out[2,0] =
|
|
345
|
-
out[2,1] = -
|
|
346
|
-
out[2,2] =
|
|
422
|
+
det = M[0,0]*M[1,1]*M[2,2] - M[0,0]*M[1,2]*M[2,1] - M[0,1]*M[1,0]*M[2,2] + M[0,1]*M[1,2]*M[2,0] + M[0,2]*M[1,0]*M[2,1] - M[0,2]*M[1,1]*M[2,0]
|
|
423
|
+
out[0,0] = M[1,1]*M[2,2] - M[1,2]*M[2,1]
|
|
424
|
+
out[0,1] = -M[0,1]*M[2,2] + M[0,2]*M[2,1]
|
|
425
|
+
out[0,2] = M[0,1]*M[1,2] - M[0,2]*M[1,1]
|
|
426
|
+
out[1,0] = -M[1,0]*M[2,2] + M[1,2]*M[2,0]
|
|
427
|
+
out[1,1] = M[0,0]*M[2,2] - M[0,2]*M[2,0]
|
|
428
|
+
out[1,2] = -M[0,0]*M[1,2] + M[0,2]*M[1,0]
|
|
429
|
+
out[2,0] = M[1,0]*M[2,1] - M[1,1]*M[2,0]
|
|
430
|
+
out[2,1] = -M[0,0]*M[2,1] + M[0,1]*M[2,0]
|
|
431
|
+
out[2,2] = M[0,0]*M[1,1] - M[0,1]*M[1,0]
|
|
347
432
|
out = out*det
|
|
348
433
|
return out
|
|
349
434
|
|
|
350
|
-
|
|
351
435
|
@njit(cache=True, nogil=True)
|
|
352
|
-
def matmul(
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
436
|
+
def matmul(M: np.ndarray, vecs: np.ndarray):
|
|
437
|
+
"""Executes a basis transformation of vectors (3,N) with a basis matrix M
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
M (np.ndarray): A (3,3) basis matrix
|
|
441
|
+
vec (np.ndarray): A (3,N) set of coordinates
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
np.ndarray: The transformed (3,N) set of vectors
|
|
445
|
+
"""
|
|
446
|
+
out = np.empty((3,vecs.shape[1]), dtype=vecs.dtype)
|
|
447
|
+
out[0,:] = M[0,0]*vecs[0,:] + M[0,1]*vecs[1,:] + M[0,2]*vecs[2,:]
|
|
448
|
+
out[1,:] = M[1,0]*vecs[0,:] + M[1,1]*vecs[1,:] + M[1,2]*vecs[2,:]
|
|
449
|
+
out[2,:] = M[2,0]*vecs[0,:] + M[2,1]*vecs[1,:] + M[2,2]*vecs[2,:]
|
|
357
450
|
return out
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
"""
|
|
20
|
+
THESE FUNCTIONS ARE MEANT TO QUICKLY COUPLE COORDINATES ON TWO PERIODIC
|
|
21
|
+
BOUNDARIES IN THE SMALLEST AMOUNT OF TIME WITHOUT RISKING FLOAT ROUNDING ERRORS.
|
|
22
|
+
|
|
23
|
+
THE MAPPING IS DONE BY BY SIMPLY FINDING THE CLOSEST COORDINATE AFTER PROJECTION
|
|
24
|
+
BY SEARCHING A LIST SORTED DICTIONARY WISE ON 3D COORDINATES.
|
|
25
|
+
|
|
26
|
+
ALL PAIRED NODES ARE NO LONGER VISITED
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
from numba import njit, f8, i8
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
############################################################
|
|
34
|
+
# NUMBA COMPILED FUNCTION #
|
|
35
|
+
############################################################
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@njit(i8[:,:](f8[:,:], i8[:], i8[:], f8[:], f8), cache=True, nogil=True)
|
|
39
|
+
def link_coords(coords: np.ndarray, ids1: np.ndarray, ids2: np.ndarray, disp: np.ndarray, dsmax: float) -> np.ndarray:
|
|
40
|
+
D = dsmax**2
|
|
41
|
+
N = ids1.shape[0]
|
|
42
|
+
ids2_mapped = np.zeros_like(ids2)
|
|
43
|
+
|
|
44
|
+
available = np.ones_like(ids2)
|
|
45
|
+
id_start = 0
|
|
46
|
+
|
|
47
|
+
for i1 in range(N):
|
|
48
|
+
ictr = 0
|
|
49
|
+
c1 = coords[:,ids1[i1]]
|
|
50
|
+
|
|
51
|
+
for i2 in range(id_start, N):
|
|
52
|
+
if available[i2] == 0:
|
|
53
|
+
continue
|
|
54
|
+
c2 = coords[:,ids2[i2]]-disp
|
|
55
|
+
dist = (c2[0]-c1[0])**2 + (c2[1]-c1[1])**2 + (c2[2]-c1[2])**2
|
|
56
|
+
if dist > D:
|
|
57
|
+
ictr += 1
|
|
58
|
+
continue
|
|
59
|
+
if ictr==0:
|
|
60
|
+
id_start += 1
|
|
61
|
+
ids2_mapped[i1] = ids2[i2]
|
|
62
|
+
available[i2] = 0
|
|
63
|
+
break
|
|
64
|
+
|
|
65
|
+
out = np.zeros((2, N), dtype=np.int64)
|
|
66
|
+
out[0,:] = ids1
|
|
67
|
+
out[1,:] = ids2_mapped
|
|
68
|
+
return out
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
############################################################
|
|
72
|
+
# MAIN PYTHON INTERFACE #
|
|
73
|
+
############################################################
|
|
74
|
+
|
|
75
|
+
def pair_coordinates(coords: np.ndarray, ids1: list[int], ids2: list[int], disp: np.ndarray, dsmax: float) -> dict[int, int]:
|
|
76
|
+
""" This function finds the mapping between a total coordinate set and two lits of indices.
|
|
77
|
+
|
|
78
|
+
The indices correspond to two faces that are identical but displaced (mesh centroids of periodic boundaries).
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
coords (np.ndarray): A total set of coordinates
|
|
82
|
+
ids1 (list[int]): The indices of the source set
|
|
83
|
+
ids2 (list[int]): The indices of the to-be-matched set
|
|
84
|
+
disp (np.ndarray): The displacement vector of shape (3,)
|
|
85
|
+
dsmax (float): The maximum allowed displacement in matchiing
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
dict[int, int]: An int,int mapping of the indices.
|
|
89
|
+
"""
|
|
90
|
+
ids1_c_sorted = sorted(ids1, key= lambda x: tuple(coords[:,x]))
|
|
91
|
+
ids2_c_sorted = sorted(ids2, key= lambda x: tuple(coords[:,x]-disp))
|
|
92
|
+
|
|
93
|
+
mapping = link_coords(coords, np.array(ids1_c_sorted), np.array(ids2_c_sorted), disp, dsmax)
|
|
94
|
+
|
|
95
|
+
mapping = {i: j for i,j in zip(mapping[0,:], mapping[1,:])}
|
|
96
|
+
|
|
97
|
+
return mapping
|
emerge/_emerge/periodic.py
CHANGED
|
@@ -7,6 +7,11 @@ from .bc import Periodic
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
############################################################
|
|
12
|
+
# FUNCTIONS #
|
|
13
|
+
############################################################
|
|
14
|
+
|
|
10
15
|
def _rotnorm(v: np.ndarray) -> np.ndarray:
|
|
11
16
|
"""Rotate 3D vector field v 90° counterclockwise around z axis.
|
|
12
17
|
|
|
@@ -33,6 +38,11 @@ def _pair_selection(f1: FaceSelection, f2: FaceSelection, translation: tuple[flo
|
|
|
33
38
|
|
|
34
39
|
|
|
35
40
|
|
|
41
|
+
############################################################
|
|
42
|
+
# BASE PERIODIC CELL CLASS #
|
|
43
|
+
############################################################
|
|
44
|
+
|
|
45
|
+
|
|
36
46
|
class PeriodicCell:
|
|
37
47
|
|
|
38
48
|
def __init__(self,
|
|
@@ -122,6 +132,12 @@ class PeriodicCell:
|
|
|
122
132
|
def port_face(self, z: float):
|
|
123
133
|
raise NotImplementedError('')
|
|
124
134
|
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
############################################################
|
|
138
|
+
# RECTANGULAR TILING #
|
|
139
|
+
############################################################
|
|
140
|
+
|
|
125
141
|
class RectCell(PeriodicCell):
|
|
126
142
|
"""This class represents the unit cell environment of a regular rectangular tiling.
|
|
127
143
|
|
|
@@ -175,6 +191,12 @@ class RectCell(PeriodicCell):
|
|
|
175
191
|
length = z2-z1
|
|
176
192
|
return poly.extrude(length, cs=GCS.displace(0,0,z1))
|
|
177
193
|
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
############################################################
|
|
197
|
+
# HEXAGONAL TILING #
|
|
198
|
+
############################################################
|
|
199
|
+
|
|
178
200
|
class HexCell(PeriodicCell):
|
|
179
201
|
|
|
180
202
|
def __init__(self,
|