-
Notifications
You must be signed in to change notification settings - Fork 22
/
meshtools.py
1604 lines (1431 loc) · 68 KB
/
meshtools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import copy
from itertools import product
from math import atan, cos, log, pi, sin, sqrt
import numpy as np
from pymech.core import HexaData
from pymech.log import logger
# ==============================================================================
def extrude(mesh: HexaData, z, bc1="P", bc2="P", internal_bcs=True):
"""Extrudes a 2D mesh into a 3D one
Parameters
----------
mesh : :class:`pymech.core.HexaData`
2D mesh structure to extrude
zmin : float
min value of the z coordinate to extrude to
zmax : float
max value of the z coordinate to extrude to
z : float 1d array
z coordinates at which to extrude the mesh
bc1, bc2 : str
the boundary conditions to use at each end
internal_bcs : bool
if True, build mesh connectivity using internal 'E' boundary conditions
(note that those are not used by Nek5000 and will not be written to binary .re2 files).
"""
if mesh.ndim != 2:
logger.critical("The mesh to extrude must be 2D")
return -1
if mesh.lr1 != [2, 2, 1]:
logger.critical("Only mesh structures can be extruded (lr1 = [2, 2, 1])")
return -2
if mesh.var[0] < 2:
logger.critical("The mesh to extrude must contain (x, y) geometry")
return -3
if (bc1 == "P" and bc2 != "P") or (bc1 != "P" and bc2 == "P"):
logger.critical(
"Inconsistent boundary conditions: one end is 'P' but the other isn't"
)
return -4
# copy the structure and make it 3D
mesh3d = copy.deepcopy(mesh)
if not internal_bcs:
# if we don't build proper internal boundary conditions, we can get rid
# of all of them to make the data cleaner
delete_internal_bcs(mesh3d)
mesh3d.lr1 = [2, 2, 2]
mesh3d.var = [3, 0, 0, 0, 0] # remove anything that isn't geometry for now
nel2d = mesh.nel
nz = len(z) - 1
nel3d = mesh.nel * nz
nbc = mesh.nbc
mesh3d.nel = nel3d
mesh3d.ndim = 3
# The curved sides will also be extruded, one on each side of each element along nz
mesh3d.ncurv = 2 * nz * mesh.ncurv
# add extra copies of all elements
for k in range(nz - 1):
mesh_add = copy.deepcopy(mesh)
# fix the indexing of periodic and internal conditions
mesh_add.offset_connectivity((k + 1) * nel2d)
mesh3d.elem = mesh3d.elem + mesh_add.elem
# set the z locations and curvature
for k in range(nz):
for i in range(nel2d):
iel = i + nel2d * k
# replace the position arrays with 3D ones (with z empty)
mesh3d.elem[iel].pos = np.zeros((3, 2, 2, 2))
mesh3d.elem[iel].pos[:, :1, :, :] = mesh.elem[i].pos
mesh3d.elem[iel].pos[:, 1:2, :, :] = mesh.elem[i].pos
# fill in the z location
z1 = z[k]
z2 = z[k + 1]
mesh3d.elem[iel].pos[2, 0, :, :] = z1
mesh3d.elem[iel].pos[2, 1, :, :] = z2
# extend curvature and correct it if necessary
for icurv in range(4):
curv_type = mesh3d.elem[iel].ccurv[icurv]
# a 2D element has 4 edges that can be curved, numbered 0-3;
# the extruded 3D element can have four more (on the other side), numbered 4-7
mesh3d.elem[iel].ccurv[icurv + 4] = curv_type
mesh3d.elem[iel].curv[icurv + 4] = mesh3d.elem[iel].curv[
icurv
] # curvature params
if curv_type == "m":
# in this case the midpoint is given. (x, y) is correct but z should be set to the proper value.
mesh3d.elem[iel].curv[icurv][2] = z1
mesh3d.elem[iel].curv[icurv + 4][2] = z2
# fix the internal boundary conditions
# the end boundary conditions will be overwritten later with the proper ones
if internal_bcs:
for iel, el in enumerate(mesh3d.elem):
for ibc in range(nbc):
el.bcs[ibc, 4][0] = "E"
el.bcs[ibc, 4][1] = iel + 1
el.bcs[ibc, 4][2] = 5
el.bcs[ibc, 4][3] = iel - nel2d + 1
el.bcs[ibc, 4][4] = 6
el.bcs[ibc, 5][0] = "E"
el.bcs[ibc, 5][1] = iel + 1
el.bcs[ibc, 5][2] = 6
el.bcs[ibc, 5][3] = iel + nel2d + 1
el.bcs[ibc, 5][4] = 5
# update the conditions for side faces
for iface in range(4):
el.bcs[ibc, iface][1] = iel + 1
if el.bcs[ibc, iface][0] == "E":
# el.bcs[ibc, 0][1] ought to contain iel+1 once the mesh is valid
# but for now it should be off by a factor of nel2d because it is a copy of an element in the first slice
offset = iel - el.bcs[ibc, iface][1] + 1
el.bcs[ibc, iface][3] = el.bcs[ibc, iface][3] + offset
# now fix the end boundary conditions
# face 5 is at zmin and face 6 is at zmax (with Nek indexing, corresponding to 4 and 5 in Python)
for i in range(nel2d):
for ibc in range(nbc):
i1 = i + (nz - 1) * nel2d # index of the face on the zmax side
mesh3d.elem[i].bcs[ibc, 4][0] = bc1
mesh3d.elem[i].bcs[ibc, 4][1] = i + 1
mesh3d.elem[i].bcs[ibc, 4][2] = 5
mesh3d.elem[i1].bcs[ibc, 5][0] = bc2
mesh3d.elem[i1].bcs[ibc, 5][1] = i1 + 1
mesh3d.elem[i1].bcs[ibc, 5][2] = 6
# fix the matching faces for the periodic conditions
if bc1 == "P":
mesh3d.elem[i].bcs[ibc, 4][3] = i1 + 1
mesh3d.elem[i].bcs[ibc, 4][4] = 6
if bc2 == "P":
mesh3d.elem[i1].bcs[ibc, 5][3] = i + 1
mesh3d.elem[i1].bcs[ibc, 5][4] = 5
# return the extruded mesh
return mesh3d
# ==============================================================================
def extrude_refine(
mesh2D, z, bc1="P", bc2="P", fun=None, funpar=None, imesh_high=0, internal_bcs=True
):
r"""Extrudes a 2D mesh into a 3D one, following the pattern
.. code-block::
_____ _____ _____ _____
| | | | |
| | | | |
| | | | |
|_____|_____|_____|_____|
| /|\ | /|\ |
|__ / | \ __|__ / | \ __| (fun (with parameter funpar) should change change sign in the mid element)
| | | | | | | | | (half of the mid elements are also divided in 2 in (x,y)-plane)
|__|__|__|__|__|__|__|__|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | (imesh_high is the index of mesh with higher intended discretization in z)
|__|__|__|__|__|__|__|__|
The pattern is similar to "Picture Frame" of an ancient NEKTON manual (https://www.mcs.anl.gov/~fischer/Nek5000/nekmanual.pdf).
If the mid elements have curvature, the extrusion might modify it. Do not split in regions where the value of curvature parameters is very important.
Parameters
----------
mesh2D : :class:`pymech.core.HexaData`
2D mesh structure to extrude
z : float array
list of z values of the most refined zones of the extruded mesh
bc : str
the boundary condition to use at the ends
fun: function
list of functions that define the splitting lines for different discretization meshes (default: empty, in which case the simple extrusion function `extrude` is called instead)
funpar: list
list of parameters for functions that define the splitting lines for different discretization meshes (default: None, equivalent to an array of zeroes)
imesh_high : int
index of fun that defines the mesh with higher discretization. Example: 0, is the most internal mesh; 1 is the second most internal mesh, etc (default: the most internal mesh, imesh_high=0)
"""
# Consistency checks: Initial grid
if mesh2D.ndim != 2:
logger.critical("The mesh to extrude must be 2D")
return -1
if mesh2D.lr1 != [2, 2, 1]:
logger.critical("Only mesh structures can be extruded (lr1 = [2, 2, 1])")
return -2
if mesh2D.var[0] < 2:
logger.critical("The mesh to extrude must contain (x, y) geometry")
return -3
# Consistency checks: Periodic boundary condition
if (bc1 == "P" and bc2 != "P") or (bc1 != "P" and bc2 == "P"):
logger.critical(
"Inconsistent boundary conditions: one end is 'P' but the other isn't"
)
return -4
# Consistency checks: Functions that define the splitting lines
nsplit = len(fun)
if funpar is not None and len(funpar) != nsplit:
logger.critical(
f"The length of funpar ({len(funpar)}) must match the length of par ({nsplit})!"
)
return -5
# number of elements in the z direction
nz = len(z) - 1
# Consistency checks: if nz is divided by 4 (or 8, or 16, etc)
if (nz % 2 ** abs(imesh_high + 1) != 0) or (
nz % 2 ** abs(nsplit - imesh_high + 1) != 0
):
logger.critical(
f"Inconsistent elements to extrude: the number of elements ({nz}) must be a multiple of {max([2**abs(imesh_high + 1), 2**abs(nsplit - imesh_high + 1)])}"
)
return -10
# If fun is not defined, there is no splitting to be done. Call simple extrusion and end routine
if fun is None:
logger.info("Splitting function not defined. Calling simple extrusion routine.")
mesh3D = extrude(mesh2D, z, bc1, bc2)
return mesh3D
mesh2D_ext = copy.deepcopy(mesh2D)
# get rid of internal boundary conditions if they are not requested
if not internal_bcs:
delete_internal_bcs(mesh2D_ext)
meshes2D = [] # list of 2D meshes
meshes3D = [] # list of 3D meshes
# Splitting 2D meshes
# sorts element of the 2D mesh into layers: most refined, first split, second most refined,
# second split, etc, until the least refined stored into mesh2D_ext.
for k in range(nsplit):
meshes2D.append(copy.deepcopy(mesh2D_ext))
meshes2D.append(copy.deepcopy(mesh2D_ext))
elems_int = []
elems_mid = []
elems_ext = []
for iel in range(mesh2D_ext.nel):
it = 0
xvec = np.zeros((4, 1))
yvec = np.zeros((4, 1))
rvec = np.zeros((4, 1))
for i in range(2):
for j in range(2):
xvec[it] = mesh2D_ext.elem[iel].pos[0, 0, j, i]
yvec[it] = mesh2D_ext.elem[iel].pos[1, 0, j, i]
rvec[it] = fun[k](xvec[it], yvec[it], funpar[k])
it += 1
if (
max(rvec) <= 0.0
): # the element belongs to the internal (more refined) mesh
elems_int.append(iel)
elif (
min(rvec) > 0.0
): # the element belongs to the external (less refined) mesh
elems_ext.append(iel)
else: # the element belongs to the intermediate mesh and will be split
elems_mid.append(iel)
external_bc = ""
if internal_bcs:
# dummy "external" boundary condition that will be used between parts of meshes
# to be merged together later in order to mark the faces to merge.
# This is only necessary if we want to build the internal connectivity.
external_bc = "con"
keep_elements(meshes2D[2 * k], elems_int, external_bc=external_bc)
keep_elements(meshes2D[2 * k + 1], elems_mid, external_bc=external_bc)
keep_elements(mesh2D_ext, elems_ext, external_bc=external_bc)
logger.debug(f"Mesh2D {2 * k} elements: {meshes2D[2 * k].nel}")
logger.debug(f"Mesh2D {2 * k + 1} elements: {meshes2D[2 * k + 1].nel}")
# End of splitting, remaining is the last mesh: Mesh_ext
logger.debug(f"Mesh2Dext elements: {mesh2D_ext.nel}")
# Update curvature metadata for all sub-meshes
mesh2D_ext.update_ncurv()
for mesh_part in meshes2D:
mesh_part.update_ncurv()
# Extruding meshes
logger.info("Extruding meshes")
for k in range(nsplit):
# divide number of elements by 2**(coarsening level)
n_local = nz // 2 ** abs(k - imesh_high)
# select z coordinates for coarsened elements
z_local = z[:: int(2 ** abs(k - imesh_high))]
if k < imesh_high:
def fun_local(xpos, ypos, rlim):
return -fun[k](xpos, ypos, rlim)
n_mid = 2 * n_local
z_mid = z[:: int(2 ** abs(k - imesh_high + 1))]
else:
fun_local = fun[k]
n_mid = n_local
z_mid = z_local
if n_mid % 4 != 0:
logger.critical(
f"Inconsistent elements to extrude: n ({n_mid}) is not a multiple of 4."
)
return -11
meshes3D.append(
extrude(
meshes2D[2 * k], z_local, bc1=bc1, bc2=bc2, internal_bcs=internal_bcs
)
)
meshes3D.append(
extrude_mid(
meshes2D[2 * k + 1],
z_mid,
bc1,
bc2,
fun_local,
funpar=funpar[k],
internal_bcs=internal_bcs,
)
)
logger.debug(f"Mesh3D {2 * k} elements: {meshes3D[2 * k].nel}")
logger.debug(f"Mesh3D {2 * k + 1} elements: {meshes3D[2 * k + 1].nel}")
n_local = nz // 2 ** abs(nsplit - imesh_high)
z_local = z[:: int(2 ** abs(nsplit - imesh_high))]
mesh3D_ext = extrude(
mesh2D_ext, z_local, bc1=bc1, bc2=bc2, internal_bcs=internal_bcs
)
logger.debug(f"Mesh3Dext elements: {mesh3D_ext.nel}")
# Merging meshes
logger.info("Merging meshes")
mesh3D = mesh3D_ext
for mesh_part in meshes3D:
mesh3D.merge(mesh_part, ignore_all_bcs=not internal_bcs)
logger.info(f"Merging done. Total elements: {mesh3D.nel}")
# update curve metadata
mesh3D.update_ncurv()
# return the extruded mesh
return mesh3D
# =================================================================================
def extrude_mid(mesh, z, bc1, bc2, fun, funpar=0.0, internal_bcs=True):
r"""Extrudes the mid elments of the 2D mesh into a 3D one. Following the pattern:
.. code-block::
_____ _____ _____ _____
|1 /|\ 4| /|\ |
|__ / | \ __|__ / | \ __| (fun (with parameter funpar) should change change sign in the mid element)
|0 |2 |3 | 5| | | | | (half of the mid elements are also divided in 2 in (x, y)-plane)
|__|__|__|__|__|__|__|__| (numbers in the figure indicate the indices (iel + 0; iel + 1; etc))
Parameters
----------
mesh : :class:`pymech.core.HexaData`
2D mesh structure to extrude
z : float
list of z values of the nodes of the elements of the extruded mesh in the high discretization region (len(z)-1 must be divide by 4)
bc : str
the boundary condition to use at the ends
fun : function
function that define the splitting lines for different discretization meshes
funpar : not defined, depends on the function
parameter for functions that define the splitting lines for different discretization meshes (default: zero, can be used for when funpar is not needed inside fun)
Suggestion: see function extrude_split to understand how to call extrude_mid
"""
# Consistency checks: Initial grid
if mesh.ndim != 2:
logger.critical("The mesh to extrude must be 2D")
return -1
if mesh.lr1 != [2, 2, 1]:
logger.critical("Only mesh structures can be extruded (lr1 = [2, 2, 1])")
return -2
if mesh.var[0] < 2:
logger.critical("The mesh to extrude must contain (x, y) geometry")
return -3
if (bc1 == "P" and bc2 != "P") or (bc1 != "P" and bc2 == "P"):
logger.critical(
"Inconsistent boundary conditions: one end is 'P' but the other isn't"
)
return -4
nz = len(z) - 1
z1 = np.zeros((nz, 1))
z2 = np.zeros((nz, 1))
z1 = z[0:nz]
z2 = z[1 : nz + 1]
if nz % 4 != 0:
logger.critical("Inconsistent elements to extrude: nz must be divided by 4")
return -5
# copy the structure and make it 3D
mesh3d = copy.deepcopy(mesh)
# add extra copies of all elements
for k in range(6 * (nz // 4) - 1):
mesh_add = copy.deepcopy(mesh)
mesh3d.merge(mesh_add, ignore_all_bcs=True)
# make the mesh 3D
mesh3d.lr1 = [2, 2, 2]
mesh3d.var = [3, 0, 0, 0, 0] # remove anything that isn't geometry for now
nel2d = mesh.nel
nel3d = (
nel2d * 6 * (nz // 4)
) # every mid-extrusion of a 2d-element creates 6 3d-elements, while the usual extrusion creates 4 in the high discretized grid and 2 in the low discretized grid
nbc = mesh.nbc
mesh3d.nel = nel3d
mesh3d.ndim = 3
# The curved sides will also be extruded, one on each side of each element along nz
mesh3d.ncurv = 2 * nz * mesh.ncurv
# set the x, y, z locations and curvature
for k in range(0, nz, 4):
for i in range(nel2d):
iel = 6 * (i + nel2d * (k // 4))
for iell in range(6):
mesh3d.elem[iel + iell] = copy.deepcopy(mesh.elem[i])
mesh3d.elem[iel + iell].pos = np.zeros((3, 2, 2, 2))
xvec = np.zeros((2, 2))
yvec = np.zeros((2, 2))
rvec = np.zeros((2, 2))
index_lo = np.zeros(
(2, 2), dtype=int
) # index [ix, iy] of the two low points
index_hi = np.zeros(
(2, 2), dtype=int
) # index [ix, iy] of the two high points
iindex_lo = 0 # index of low points (among the four corners), that have a negative image by the function
iindex_hi = (
0 # index of high points, that have a positive image by the function
)
iedgelat = np.zeros((2), dtype=int)
iedgeconlat = np.zeros((2), dtype=int)
# find which of the four corners are low points and high points; there must be two of each.
for ii in range(2):
for jj in range(2):
xvec[jj, ii] = mesh.elem[i].pos[0, 0, jj, ii]
yvec[jj, ii] = mesh.elem[i].pos[1, 0, jj, ii]
rvec[jj, ii] = fun(xvec[jj, ii], yvec[jj, ii], funpar)
if rvec[jj, ii] <= 0.0:
if iindex_lo > 1:
logger.critical(
"Mid element not consistent. Criteria must divide elements with 2 points on each side."
)
return -11
index_lo[iindex_lo, :] = [jj, ii]
iindex_lo += 1
else:
if iindex_hi > 1:
logger.critical(
"Mid element not consistent. Criteria must divide elements with 2 points on each side."
)
return -11
index_hi[iindex_hi, :] = [jj, ii]
iindex_hi += 1
if (iindex_lo != 2) or (iindex_hi != 2):
logger.critical(
"Mid element not consistent. Criteria must divide elements with 2 points on each side."
)
return -11
# find the indices of edges, for curvature and boundary condition
#
# iedgehi is the index of the edge of element iel + 0 that is the intersection between iel + 0 and iel + 1 (high edge).
# iedgelo is the index of the edge of element iel + 1 that is the intersection (low edge).
# iedgelat are the indices of the lateral (splitted) edges.
# iedgeconlat are the indices of the edges (edge in z-direction) of elements iel + 2
# and iel + 3 that connect to the respective lateral edges.
if (index_lo[0, :] == [0, 0]).all():
if (index_hi[0, :] == [0, 1]).all():
iedgehi = 1
iedgelo = 3
iedgelat[0] = 0
iedgelat[1] = 2
iedgeconlat[0] = 9
iedgeconlat[1] = 10
else:
iedgehi = 2
iedgelo = 0
iedgelat[0] = 3
iedgelat[1] = 1
iedgeconlat[0] = 11
iedgeconlat[1] = 10
elif (index_lo[0, :] == [1, 0]).all():
iedgehi = 0
iedgelo = 2
iedgelat[0] = 3
iedgelat[1] = 1
iedgeconlat[0] = 8
iedgeconlat[1] = 9
elif (index_lo[0, :] == [0, 1]).all():
iedgehi = 3
iedgelo = 1
iedgelat[0] = 0
iedgelat[1] = 2
iedgeconlat[0] = 8
iedgeconlat[1] = 11
# find x and y locations
poslo = mesh.elem[i].pos[:, :1, index_lo[:, 0], index_lo[:, 1]]
poshi = mesh.elem[i].pos[:, :1, index_hi[:, 0], index_hi[:, 1]]
# mid position is influenced by curvature
posmid = 0.5 * (
mesh.elem[i].pos[:, :1, index_lo[:, 0], index_lo[:, 1]]
+ mesh.elem[i].pos[:, :1, index_hi[:, 0], index_hi[:, 1]]
)
for ilat in range(2):
# finds the mid points of lateral edges (also considering curvature)
posmid[:, 0, ilat] = edge_mid(mesh.elem[i], iedgelat[ilat])
# fill in the x and y location
mesh3d.elem[iel].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = poslo
mesh3d.elem[iel].pos[:, 0:2, index_hi[:, 0], index_hi[:, 1]] = posmid
mesh3d.elem[iel + 1].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = posmid
mesh3d.elem[iel + 1].pos[:, 0:2, index_hi[:, 0], index_hi[:, 1]] = poshi
mesh3d.elem[iel + 2].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = poslo
mesh3d.elem[iel + 2].pos[:, :1, index_hi[:, 0], index_hi[:, 1]] = posmid
mesh3d.elem[iel + 2].pos[:, 1:2, index_hi[:, 0], index_hi[:, 1]] = poshi
mesh3d.elem[iel + 3].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = poslo
mesh3d.elem[iel + 3].pos[:, :1, index_hi[:, 0], index_hi[:, 1]] = poshi
mesh3d.elem[iel + 3].pos[:, 1:2, index_hi[:, 0], index_hi[:, 1]] = posmid
mesh3d.elem[iel + 4].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = posmid
mesh3d.elem[iel + 4].pos[:, 0:2, index_hi[:, 0], index_hi[:, 1]] = poshi
mesh3d.elem[iel + 5].pos[:, 0:2, index_lo[:, 0], index_lo[:, 1]] = poslo
mesh3d.elem[iel + 5].pos[:, 0:2, index_hi[:, 0], index_hi[:, 1]] = posmid
# fill in the z location
mesh3d.elem[iel].pos[2, 0, :, :] = z1[k]
mesh3d.elem[iel].pos[2, 1, :, :] = z2[k]
mesh3d.elem[iel + 1].pos[2, 0, :, :] = z1[k]
mesh3d.elem[iel + 1].pos[2, 1, index_lo[0, 0], index_lo[0, 1]] = z2[k]
mesh3d.elem[iel + 1].pos[2, 1, index_lo[1, 0], index_lo[1, 1]] = z2[k]
mesh3d.elem[iel + 1].pos[2, 1, index_hi[0, 0], index_hi[0, 1]] = z2[k + 1]
mesh3d.elem[iel + 1].pos[2, 1, index_hi[1, 0], index_hi[1, 1]] = z2[k + 1]
mesh3d.elem[iel + 2].pos[2, 0, :, :] = z1[k + 1]
mesh3d.elem[iel + 2].pos[2, 1, :, :] = z2[k + 1]
mesh3d.elem[iel + 3].pos[2, 0, :, :] = z1[k + 2]
mesh3d.elem[iel + 3].pos[2, 1, :, :] = z2[k + 2]
mesh3d.elem[iel + 4].pos[2, 1, :, :] = z2[k + 3]
mesh3d.elem[iel + 4].pos[2, 0, index_lo[0, 0], index_lo[0, 1]] = z1[k + 3]
mesh3d.elem[iel + 4].pos[2, 0, index_lo[1, 0], index_lo[1, 1]] = z1[k + 3]
mesh3d.elem[iel + 4].pos[2, 0, index_hi[0, 0], index_hi[0, 1]] = z1[k + 2]
mesh3d.elem[iel + 4].pos[2, 0, index_hi[1, 0], index_hi[1, 1]] = z1[k + 2]
mesh3d.elem[iel + 5].pos[2, 0, :, :] = z1[k + 3]
mesh3d.elem[iel + 5].pos[2, 1, :, :] = z2[k + 3]
for icurv in range(4):
# Curvature type 's' acts on faces, not edges. Does not make sense for extruded mesh. Changing to 'C'.
if mesh.elem[i].ccurv[icurv] == "s":
logger.warn(
f"Curvature s on element {i + 1}. Not consistent with extrusion, changing to C"
)
mesh.elem[i].ccurv[icurv] == "C"
mesh.elem[i].ccurv[icurv][0] = mesh.elem[i].ccurv[icurv][4]
mesh.elem[i].ccurv[icurv][1:4] = 0.0
elif (
(mesh.elem[i].ccurv[icurv] != "")
and (mesh.elem[i].ccurv[icurv] != "m")
and (mesh.elem[i].ccurv[icurv] != "C")
):
logger.warn(f"Curvature unknown on element {i + 1}")
# extend curvature and correct it if necessary
# calculate coordinates of midsize-node for every curvature type, except both empty (even if both are 'C'). Then find radius, if applicable. 'm' takes precendence over 'C'.
# if mesh.elem[i].ccurv[iedgehi] != mesh.elem[i].ccurv[iedgelo]:
if mesh.elem[i].ccurv[iedgehi] != "" or mesh.elem[i].ccurv[iedgelo] != "":
midpointhi = edge_mid(mesh.elem[i], iedgehi)
midpointlo = edge_mid(mesh.elem[i], iedgelo)
midpointmid = 0.5 * (posmid[:, 0, 0] + posmid[:, 0, 1]) + 0.5 * (
midpointhi
- 0.5 * (poshi[:, 0, 0] + poshi[:, 0, 1])
+ midpointlo
- 0.5 * (poslo[:, 0, 0] + poslo[:, 0, 1])
)
if (
mesh.elem[i].ccurv[iedgehi] == "m"
or mesh.elem[i].ccurv[iedgelo] == "m"
):
mesh3d.elem[iel].ccurv[iedgehi] = "m"
mesh3d.elem[iel + 1].ccurv[iedgelo] = "m"
mesh3d.elem[iel].curv[iedgehi][:3] = midpointmid
mesh3d.elem[iel + 1].curv[iedgelo][:3] = midpointmid
elif (
mesh.elem[i].ccurv[iedgehi] == "C"
or mesh.elem[i].ccurv[iedgelo] == "C"
):
midpointmid[2] = z1[k]
curvmid = edge_circle(mesh3d.elem[iel], iedgehi, midpointmid)
if curvmid[0] == 0.0:
mesh3d.elem[iel].ccurv[iedgehi] = ""
mesh3d.elem[iel + 1].ccurv[iedgelo] = ""
mesh3d.elem[iel].curv[iedgehi][:4] = 0.0
mesh3d.elem[iel + 1].curv[iedgelo][:4] = 0.0
else:
curvmid[1:4] = 0.0
mesh3d.elem[iel].ccurv[iedgehi] = "C"
mesh3d.elem[iel + 1].ccurv[iedgelo] = "C"
mesh3d.elem[iel].curv[iedgehi][:4] = curvmid
mesh3d.elem[iel + 1].curv[iedgelo][:4] = -curvmid
else:
logger.warn(
f"Splitted element curvature unknown on element {i + 1} of mid mesh. Removing curvature."
)
# For cases not implemented, remove curvature
mesh3d.elem[iel].ccurv[iedgehi] = ""
mesh3d.elem[iel + 1].ccurv[iedgelo] = ""
mesh3d.elem[iel].curv[iedgehi] = 0.0 * mesh.elem[i].curv[iedgehi]
mesh3d.elem[iel + 1].curv[iedgelo] = mesh3d.elem[iel].curv[iedgehi]
for ilat in range(2):
# Fixing curvature of edges divided in half. For curv_type == 'C', it is not a true extrusion - 'diagonal edges' not consistent with 'C'.
if mesh.elem[i].ccurv[iedgelat[ilat]] == "m":
# coordinates of midsize-node is approximated. Considering an edge aligned with the x-axis, the position would be (ym_new = 3/4*ym_old = 1/2*ym_old(mean y-position) + 1/4*ym_old(distance)) at xm_new=(x2-x1)/4. This comes from parabolic curve (however, it is not exactly midsize)
dmid = (
(poshi[0, 0, ilat] - poslo[0, 0, ilat])
* (poslo[1, 0, ilat] - posmid[1, 0, ilat])
- (poslo[0, 0, ilat] - posmid[0, 0, ilat])
* (poshi[1, 0, ilat] - poslo[1, 0, ilat])
) / (
(poshi[0, 0, ilat] - poslo[0, 0, ilat]) ** 2
+ (poshi[1, 0, ilat] - poslo[1, 0, ilat]) ** 2
)
mesh3d.elem[iel].curv[iedgelat[ilat]][0] = 0.5 * (
poslo[0, 0, ilat] + posmid[0, 0, ilat]
) + dmid / 4.0 * (poshi[1, 0, ilat] - poslo[1, 0, ilat])
mesh3d.elem[iel + 1].curv[iedgelat[ilat]][0] = 0.5 * (
posmid[0, 0, ilat] + poshi[0, 0, ilat]
) + dmid / 4.0 * (poshi[1, 0, ilat] - poslo[1, 0, ilat])
mesh3d.elem[iel].curv[iedgelat[ilat]][1] = 0.5 * (
poslo[1, 0, ilat] + posmid[1, 0, ilat]
) - dmid / 4.0 * (poshi[0, 0, ilat] - poslo[0, 0, ilat])
mesh3d.elem[iel + 1].curv[iedgelat[ilat]][1] = 0.5 * (
posmid[1, 0, ilat] + poshi[1, 0, ilat]
) - dmid / 4.0 * (poshi[0, 0, ilat] - poslo[0, 0, ilat])
elif mesh.elem[i].ccurv[iedgelat[ilat]] == "C":
# if the lateral edge has curvature 'C', the diagonal edges connected to it (iedgeconlat of elements iel + 2 and iel + 3) would have curvature 'C', which are inconsistent with edges 8-12 inside Nek5000 (because these are supposed to be edges in z-direction). Changing to curvature 'm' for elements iel + 1 (and iel + 2, iel + 3, iel + 2, iel + 4)
midpointlathi = edge_mid(mesh3d.elem[iel + 1], iedgelat[ilat])
mesh3d.elem[iel + 1].curv[iedgelat[ilat]][:3] = midpointlathi
mesh3d.elem[iel + 1].ccurv[iedgelat[ilat]] = "m"
for icurv in range(4):
# a 2D element has 4 edges that can be curved, numbered 0-3;
# the extruded 3D element can have four more (on the other side), numbered 4-7
for iell in range(6):
mesh3d.elem[iel + iell].ccurv[icurv + 4] = mesh3d.elem[
iel + iell
].ccurv[icurv]
mesh3d.elem[iel + iell].curv[icurv + 4] = mesh3d.elem[
iel + iell
].curv[
icurv
] # curvature params
mesh3d.elem[iel + 2].curv[0:4] = mesh3d.elem[iel].curv[0:4]
mesh3d.elem[iel + 3].curv[4:8] = mesh3d.elem[iel].curv[0:4]
mesh3d.elem[iel + 5].curv[:] = mesh3d.elem[iel].curv
mesh3d.elem[iel + 4].curv[:] = mesh3d.elem[iel + 1].curv
mesh3d.elem[iel + 2].ccurv[0:4] = mesh3d.elem[iel].ccurv[0:4]
mesh3d.elem[iel + 3].ccurv[4:8] = mesh3d.elem[iel].ccurv[0:4]
mesh3d.elem[iel + 5].ccurv[:] = mesh3d.elem[iel].ccurv
mesh3d.elem[iel + 4].ccurv[:] = mesh3d.elem[iel + 1].ccurv
for icurv in range(4):
# z should be set to the proper value.
curv_type = mesh3d.elem[iel].ccurv[icurv]
if curv_type == "m":
izcurv = 2
mesh3d.elem[iel].curv[icurv][izcurv] = z1[k]
mesh3d.elem[iel].curv[icurv + 4][izcurv] = z2[k]
mesh3d.elem[iel + 2].curv[icurv][izcurv] = z1[k + 1]
mesh3d.elem[iel + 2].curv[icurv + 4][izcurv] = z2[k + 1]
mesh3d.elem[iel + 3].curv[icurv][izcurv] = z1[k + 2]
mesh3d.elem[iel + 3].curv[icurv + 4][izcurv] = z2[k + 2]
mesh3d.elem[iel + 5].curv[icurv][izcurv] = z1[k + 3]
mesh3d.elem[iel + 5].curv[icurv + 4][izcurv] = z2[k + 3]
curv_type = mesh3d.elem[iel + 1].ccurv[icurv]
# curvature of iel + 1 may be different from iel because of diagonal edges
if curv_type == "m":
izcurv = 2
mesh3d.elem[iel + 1].curv[icurv][izcurv] = z1[k]
mesh3d.elem[iel + 4].curv[icurv + 4][izcurv] = z2[k + 3]
if icurv == iedgehi:
mesh3d.elem[iel + 1].curv[iedgehi + 4][izcurv] = z2[k + 1]
mesh3d.elem[iel + 4].curv[iedgehi][izcurv] = z2[k + 1]
elif icurv == iedgelo:
mesh3d.elem[iel + 1].curv[iedgelo + 4][izcurv] = z1[k + 1]
mesh3d.elem[iel + 4].curv[iedgelo][izcurv] = z2[k + 2]
elif icurv == iedgelat[0] or icurv == iedgelat[1]:
mesh3d.elem[iel + 1].curv[icurv + 4][izcurv] = 0.5 * (
z1[k + 1] + z2[k + 1]
)
mesh3d.elem[iel + 4].curv[icurv][izcurv] = 0.5 * (
z2[k + 1] + z2[k + 2]
)
# Fixing the curvature of 3d-edges in z-direction that connects to lateral edges in trapezoidal elements (all other edges in z-direction - indices 8 to 11 - do not have curvature)
for ilat in range(2):
mesh3d.elem[iel + 2].curv[iedgeconlat[ilat]] = mesh3d.elem[
iel + 1
].curv[iedgelat[ilat] + 4]
mesh3d.elem[iel + 2].ccurv[iedgeconlat[ilat]] = mesh3d.elem[
iel + 1
].ccurv[iedgelat[ilat] + 4]
mesh3d.elem[iel + 3].curv[iedgeconlat[ilat]] = mesh3d.elem[
iel + 4
].curv[iedgelat[ilat]]
mesh3d.elem[iel + 3].ccurv[iedgeconlat[ilat]] = mesh3d.elem[
iel + 4
].ccurv[iedgelat[ilat]]
# fix the internal boundary conditions
# the end boundary conditions will be overwritten later with the proper ones
for ibc in range(nbc):
# set the conditions in faces normal to z
if internal_bcs:
for iell in range(6):
mesh3d.elem[iel + iell].bcs[ibc, 4][0] = "E"
mesh3d.elem[iel + iell].bcs[ibc, 4][1] = iel + iell + 1
mesh3d.elem[iel + iell].bcs[ibc, 4][2] = 5
mesh3d.elem[iel + iell].bcs[ibc, 4][4] = 6
mesh3d.elem[iel + iell].bcs[ibc, 5][0] = "E"
mesh3d.elem[iel + iell].bcs[ibc, 5][1] = iel + iell + 1
mesh3d.elem[iel + iell].bcs[ibc, 5][2] = 6
mesh3d.elem[iel + iell].bcs[ibc, 5][4] = 5
mesh3d.elem[iel].bcs[ibc, 4][3] = iel + 1 + 5 - 6 * nel2d
mesh3d.elem[iel].bcs[ibc, 5][3] = iel + 1 + 2
mesh3d.elem[iel + 1].bcs[ibc, 4][3] = iel + 1 + 4 - 6 * nel2d
mesh3d.elem[iel + 2].bcs[ibc, 4][3] = iel + 1
mesh3d.elem[iel + 2].bcs[ibc, 5][3] = iel + 1 + 3
mesh3d.elem[iel + 3].bcs[ibc, 4][3] = iel + 1 + 2
mesh3d.elem[iel + 3].bcs[ibc, 5][3] = iel + 1 + 5
mesh3d.elem[iel + 4].bcs[ibc, 5][3] = iel + 1 + 1 + 6 * nel2d
mesh3d.elem[iel + 5].bcs[ibc, 4][3] = iel + 1 + 3
mesh3d.elem[iel + 5].bcs[ibc, 5][3] = iel + 1 + 6 * nel2d
# Correct internal bc for mid faces of elements.
mesh3d.elem[iel].bcs[ibc, iedgehi][0] = "E"
mesh3d.elem[iel].bcs[ibc, iedgehi][3] = iel + 1 + 1
mesh3d.elem[iel].bcs[ibc, iedgehi][4] = iedgelo + 1
mesh3d.elem[iel + 1].bcs[ibc, iedgelo][0] = "E"
mesh3d.elem[iel + 1].bcs[ibc, iedgelo][3] = iel + 1
mesh3d.elem[iel + 1].bcs[ibc, iedgelo][4] = iedgehi + 1
mesh3d.elem[iel + 1].bcs[ibc, 5][0] = "E"
mesh3d.elem[iel + 1].bcs[ibc, 5][3] = iel + 1 + 2
mesh3d.elem[iel + 1].bcs[ibc, 5][4] = iedgehi + 1
mesh3d.elem[iel + 2].bcs[ibc, iedgehi][0] = "E"
mesh3d.elem[iel + 2].bcs[ibc, iedgehi][3] = iel + 1 + 1
mesh3d.elem[iel + 2].bcs[ibc, iedgehi][4] = 6
mesh3d.elem[iel + 3].bcs[ibc, iedgehi][0] = "E"
mesh3d.elem[iel + 3].bcs[ibc, iedgehi][3] = iel + 1 + 4
mesh3d.elem[iel + 3].bcs[ibc, iedgehi][4] = 5
mesh3d.elem[iel + 4].bcs[ibc, 4][0] = "E"
mesh3d.elem[iel + 4].bcs[ibc, 4][3] = iel + 1 + 3
mesh3d.elem[iel + 4].bcs[ibc, 4][4] = iedgehi + 1
mesh3d.elem[iel + 4].bcs[ibc, iedgelo][0] = "E"
mesh3d.elem[iel + 4].bcs[ibc, iedgelo][3] = iel + 1 + 5
mesh3d.elem[iel + 4].bcs[ibc, iedgelo][4] = iedgehi + 1
mesh3d.elem[iel + 5].bcs[ibc, iedgehi][0] = "E"
mesh3d.elem[iel + 5].bcs[ibc, iedgehi][3] = iel + 1 + 4
mesh3d.elem[iel + 5].bcs[ibc, iedgehi][4] = iedgelo + 1
# update the conditions for side faces.
for iface in iedgelat:
bc = mesh.elem[i].bcs[ibc, iface][0]
if bc == "P" or bc == "E":
for iell in range(6):
connected_i = mesh.elem[i].bcs[ibc, iface][3] - 1
connected_iel = 6 * (connected_i + nel2d * (k // 4)) + iell
mesh3d.elem[iel + iell].bcs[ibc, iface][3] = (
connected_iel + 1
)
mesh3d.elem[iel + iell].bcs[ibc, iface][4] = mesh.elem[
i
].bcs[ibc, iface][4]
# now fix the end boundary conditions
# face 5 is at zmin and face 6 is at zmax (with Nek indexing, corresponding to 4 and 5 in Python)
for i in range(0, 6 * nel2d, 6):
for ibc in range(nbc):
i1 = i + nel3d - 6 * nel2d + 5
mesh3d.elem[i].bcs[ibc, 4][0] = bc1
mesh3d.elem[i].bcs[ibc, 4][1] = i + 1
mesh3d.elem[i].bcs[ibc, 4][2] = 5
mesh3d.elem[i + 1].bcs[ibc, 4][0] = bc1
mesh3d.elem[i + 1].bcs[ibc, 4][1] = i + 1 + 1
mesh3d.elem[i + 1].bcs[ibc, 4][2] = 5
mesh3d.elem[i1].bcs[ibc, 5][0] = bc2
mesh3d.elem[i1].bcs[ibc, 5][1] = i1 + 1
mesh3d.elem[i1].bcs[ibc, 5][2] = 6
mesh3d.elem[i1 - 1].bcs[ibc, 5][0] = bc2
mesh3d.elem[i1 - 1].bcs[ibc, 5][1] = i1 - 1 + 1
mesh3d.elem[i1 - 1].bcs[ibc, 5][2] = 6
mesh3d.elem[i].bcs[ibc, 4][3] = 0.0
mesh3d.elem[i].bcs[ibc, 4][4] = 0.0
mesh3d.elem[i + 1].bcs[ibc, 4][3] = 0.0
mesh3d.elem[i + 1].bcs[ibc, 4][4] = 0.0
mesh3d.elem[i1].bcs[ibc, 5][3] = 0.0
mesh3d.elem[i1].bcs[ibc, 5][4] = 0.0
mesh3d.elem[i1 - 1].bcs[ibc, 5][3] = 0.0
mesh3d.elem[i1 - 1].bcs[ibc, 5][4] = 0.0
# fix the matching faces for the periodic conditions
if bc1 == "P":
mesh3d.elem[i].bcs[ibc, 4][3] = i1 + 1
mesh3d.elem[i].bcs[ibc, 4][4] = 6
mesh3d.elem[i + 1].bcs[ibc, 4][3] = i1 - 1 + 1
mesh3d.elem[i + 1].bcs[ibc, 4][4] = 6
if bc2 == "P":
mesh3d.elem[i1].bcs[ibc, 5][3] = i + 1
mesh3d.elem[i1].bcs[ibc, 5][4] = 5
mesh3d.elem[i1 - 1].bcs[ibc, 5][3] = i + 1 + 1
mesh3d.elem[i1 - 1].bcs[ibc, 5][4] = 5
# FIND THE CURVED ELEMENTS
ncurv = 0
for el in mesh3d.elem:
for iedge in range(12):
if el.ccurv[iedge] != "":
ncurv = ncurv + 1
mesh3d.ncurv = ncurv
# return the extruded mesh
return mesh3d
# =================================================================================
def edge_mid(el, iedge):
"""Finds the coordinates of the midsize-node of edge iedge of element el (in other words, if the curvature were type 'm', the values of el.curv[iedge][:3]):
Parameters
----------
el : :class:`pymech.core.HexaData`
element of mesh (usually, el=mesh.elem[i])
iedge : int
index of edge
"""
# correct if ccurv=='m', otherwise, works as allocation
midpoint = el.curv[iedge][:3]
if el.ccurv[iedge] != "m":
if iedge == 0:
pos1 = el.pos[:, 0, 0, 0]
pos2 = el.pos[:, 0, 0, 1]
elif iedge == 1:
pos1 = el.pos[:, 0, 0, 1]
pos2 = el.pos[:, 0, 1, 1]
elif iedge == 2:
pos1 = el.pos[:, 0, 1, 1]
pos2 = el.pos[:, 0, 1, 0]
elif iedge == 3:
pos1 = el.pos[:, 0, 1, 0]
pos2 = el.pos[:, 0, 0, 0]
elif iedge == 4:
pos1 = el.pos[:, 1, 0, 0]
pos2 = el.pos[:, 1, 0, 1]
elif iedge == 5:
pos1 = el.pos[:, 1, 0, 1]
pos2 = el.pos[:, 1, 1, 1]
elif iedge == 6:
pos1 = el.pos[:, 1, 1, 1]
pos2 = el.pos[:, 1, 1, 0]
elif iedge == 7:
pos1 = el.pos[:, 1, 1, 0]
pos2 = el.pos[:, 1, 0, 0]
elif iedge == 8:
pos1 = el.pos[:, 0, 0, 0]
pos2 = el.pos[:, 1, 0, 0]
elif iedge == 9:
pos1 = el.pos[:, 0, 0, 1]
pos2 = el.pos[:, 1, 0, 1]
elif iedge == 10:
pos1 = el.pos[:, 0, 1, 1]
pos2 = el.pos[:, 1, 1, 1]
elif iedge == 11:
pos1 = el.pos[:, 0, 1, 0]
pos2 = el.pos[:, 1, 1, 0]
if el.ccurv[iedge] == "":
midpoint = (pos1 + pos2) / 2.0
elif el.ccurv[iedge] == "C":
# Curvature 'C' only needs x and y. Works for 2d and extruded meshes.
if iedge > 7:
# For iedge=8-11: will give a different value to what Nek considers (Nek ignores it).
logger.warn(
"Calculating midpoint differently from Nek5000. Nek ignores it for edges 9-12."
)
radius = el.curv[iedge][0]
dmid = (
abs(radius)
- (
radius**2
- (pos2[0] - pos1[0]) ** 2 / 4.0
- (pos2[1] - pos1[1]) ** 2 / 4.0
)
** 0.5
)
midpoint[0] = (pos2[0] + pos1[0]) / 2.0 + dmid / (
(pos2[0] - pos1[0]) ** 2 + (pos2[1] - pos1[1]) ** 2
) ** (0.5) * radius / abs(radius) * (pos2[1] - pos1[1])
midpoint[1] = (pos2[1] + pos1[1]) / 2.0 - dmid / (
(pos2[0] - pos1[0]) ** 2 + (pos2[1] - pos1[1]) ** 2
) ** (0.5) * radius / abs(radius) * (pos2[0] - pos1[0])
midpoint[2] = (pos2[2] + pos1[2]) / 2.0
elif el.ccurv[iedge] == "s":
# It doesn't check if sphere is consistent with pos1 and pos2. Just assumes it is.
radius = el.curv[iedge][4]
center = el.curv[iedge][:3]
dist = (pos2 + pos1) / 2.0 - center
midpoint = (
center
+ dist * radius / (dist[0] ** 2 + dist[1] ** 2 + dist[2] ** 2) ** 0.5
)
# return the coordinate of midsize node
return midpoint
# ==============================================================================
def edge_circle(el, iedge, midpoint):
"""Finds the radius of curvature and circle center based on the midsize-node of edge iedge of element el:
Parameters
----------
el : :class:`pymech.core.HexaData`
element of mesh (usually, el=mesh.elem[i])
iedge : int
index of edge
midpoint : float
list of coordinates of midsize-node (in other words, if the curvature were type 'm', the values of el.curv[iedge][:3])
"""
if iedge == 0:
pos1 = el.pos[:, 0, 0, 0]
pos2 = el.pos[:, 0, 0, 1]
elif iedge == 1:
pos1 = el.pos[:, 0, 0, 1]
pos2 = el.pos[:, 0, 1, 1]
elif iedge == 2:
pos1 = el.pos[:, 0, 1, 1]
pos2 = el.pos[:, 0, 1, 0]
elif iedge == 3:
pos1 = el.pos[:, 0, 1, 0]
pos2 = el.pos[:, 0, 0, 0]
elif iedge == 4:
pos1 = el.pos[:, 1, 0, 0]
pos2 = el.pos[:, 1, 0, 1]
elif iedge == 5:
pos1 = el.pos[:, 1, 0, 1]
pos2 = el.pos[:, 1, 1, 1]
elif iedge == 6:
pos1 = el.pos[:, 1, 1, 1]
pos2 = el.pos[:, 1, 1, 0]
elif iedge == 7:
pos1 = el.pos[:, 1, 1, 0]
pos2 = el.pos[:, 1, 0, 0]
elif iedge == 8:
pos1 = el.pos[:, 0, 0, 0]
pos2 = el.pos[:, 1, 0, 0]