44'''
55import itertools
66import numpy as np
7- from packaging .version import Version
87from petsc4py import PETSc
9-
108import netgen .meshing as ngm
9+ from ngsPETSc .utils .utils import trim_util
1110try :
1211 import ngsolve as ngs
1312except ImportError :
@@ -16,11 +15,213 @@ class ngs:
1615 class comp :
1716 "dummy class"
1817 Mesh = type (None )
18+ try :
19+ from numba import jit
20+ numba = True
21+ except : # pylint: disable=bare-except
22+ jit = None
23+ numba = False
1924
2025FACE_SETS_LABEL = "Face Sets"
2126CELL_SETS_LABEL = "Cell Sets"
2227EDGE_SETS_LABEL = "Edge Sets"
2328
29+ if numba :
30+ @jit (nopython = True , cache = True )
31+ def build2DCells (coordinates , sIndicies , cell_indicies , start_end ):
32+ """
33+ JIT Method used to construct 2D cells
34+ """
35+ cStart = start_end [0 ]
36+ cEnd = start_end [1 ]
37+ cells = np .zeros ((cell_indicies .shape [0 ], 3 ))
38+ for i in range (cStart ,cEnd ):
39+ sIndex = sIndicies [i ]
40+ if len (sIndex )== 3 :
41+ cell = list (set (cell_indicies [i ]))
42+ A = np .zeros ((2 ,2 ))
43+ A [0 ,0 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[0 ]
44+ A [0 ,1 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[1 ]
45+ A [1 ,0 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[0 ]
46+ A [1 ,1 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[1 ]
47+ if np .linalg .det (A ) > 0 :
48+ cells [i ] = cell
49+ else :
50+ cells [i ] = np .array ([cell [0 ],cell [2 ],cell [1 ]])
51+ else :
52+ raise RuntimeError ("We only support triangles." )
53+ return cells
54+
55+ @jit (nopython = True , cache = True )
56+ def build3DCells (coordinates , sIndicies , cell_indicies , start_end ):
57+ """
58+ JIT Method used to construct 3D cells
59+ """
60+ cStart = start_end [0 ]
61+ cEnd = start_end [1 ]
62+ cells = np .zeros ((cell_indicies .shape [0 ], 4 ))
63+ for i in range (cStart ,cEnd ):
64+ sIndex = sIndicies [i ]
65+ if len (sIndex )== 4 :
66+ cell = list (set (cell_indicies [i ]))
67+ A = np .zeros ((3 ,3 ))
68+ A [0 ,0 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[0 ]
69+ A [0 ,1 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[1 ]
70+ A [0 ,2 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[2 ]
71+ A [1 ,0 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[0 ]
72+ A [1 ,1 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[1 ]
73+ A [1 ,2 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[2 ]
74+ A [2 ,0 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[0 ]
75+ A [2 ,1 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[1 ]
76+ A [2 ,2 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[2 ]
77+ if np .linalg .det (A ) > 0 :
78+ cells [i ] = cell
79+ else :
80+ cells [i ] = np .array ([cell [0 ],cell [1 ],cell [2 ], cell [2 ]])
81+ else :
82+ raise RuntimeError ("We only support tets." )
83+ return cells
84+ else :
85+ def build2DCells (coordinates , sIndicies , cell_indicies , start_end ):
86+ """
87+ Method used to construct 2D cells
88+ """
89+ cStart = start_end [0 ]
90+ cEnd = start_end [1 ]
91+ cells = np .zeros ((cell_indicies .shape [0 ], 3 ))
92+ for i in range (cStart ,cEnd ):
93+ sIndex = sIndicies [i ]
94+ if len (sIndex )== 3 :
95+ cell = list (set (cell_indicies [i ]))
96+ A = np .zeros ((2 ,2 ))
97+ A [0 ,0 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[0 ]
98+ A [0 ,1 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[1 ]
99+ A [1 ,0 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[0 ]
100+ A [1 ,1 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[1 ]
101+ if np .linalg .det (A ) > 0 :
102+ cells [i ] = cell
103+ else :
104+ cells [i ] = np .array ([cell [0 ],cell [2 ],cell [1 ]])
105+ else :
106+ raise RuntimeError ("We only support triangles." )
107+ return cells
108+
109+ def build3DCells (coordinates , sIndicies , cell_indicies , start_end ):
110+ """
111+ Method used to construct 3D cells
112+ """
113+ cStart = start_end [0 ]
114+ cEnd = start_end [1 ]
115+ cells = np .zeros ((cell_indicies .shape [0 ], 4 ))
116+ for i in range (cStart ,cEnd ):
117+ sIndex = sIndicies [i ]
118+ if len (sIndex )== 4 :
119+ cell = list (set (cell_indicies [i ]))
120+ A = np .zeros ((3 ,3 ))
121+ A [0 ,0 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[0 ]
122+ A [0 ,1 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[1 ]
123+ A [0 ,2 ] = (coordinates [cell [1 ]]- coordinates [cell [0 ]])[2 ]
124+ A [1 ,0 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[0 ]
125+ A [1 ,1 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[1 ]
126+ A [1 ,2 ] = (coordinates [cell [2 ]]- coordinates [cell [1 ]])[2 ]
127+ A [2 ,0 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[0 ]
128+ A [2 ,1 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[1 ]
129+ A [2 ,2 ] = (coordinates [cell [3 ]]- coordinates [cell [2 ]])[2 ]
130+ if np .linalg .det (A ) > 0 :
131+ cells [i ] = cell
132+ else :
133+ cells [i ] = np .array ([cell [0 ],cell [1 ],cell [3 ], cell [2 ]])
134+ else :
135+ raise RuntimeError ("We only support tets." )
136+ return cells
137+
138+ def create2DNetgenMesh (ngMesh , coordinates , plex , geoInfo ):
139+ """
140+ Method used to generate 2D NetgenMeshes
141+
142+ :arg ngMesh: the netgen mesh to be populated
143+ :arg coordinates: vertices coordinates
144+ :arg plex: PETSc DMPlex
145+ :arg geoInfo: geometric information assosciated with the Netgen mesh
146+
147+ """
148+ ngMesh .AddPoints (coordinates )
149+ cStart ,cEnd = plex .getHeightStratum (0 )
150+ vStart , _ = plex .getHeightStratum (2 )
151+ # Outside of jitted loop we put all calls to plex
152+ sIndicies = [plex .getCone (i ) for i in range (cStart ,cEnd )]
153+ cells_indicies = np .vstack ([np .hstack ([plex .getCone (sIndex [k ])- vStart
154+ for k in range (len (sIndex ))]) for sIndex in sIndicies ])
155+ ngMesh .Add (ngm .FaceDescriptor (bc = 1 ))
156+ cells = build2DCells (coordinates , sIndicies ,
157+ cells_indicies , (cStart , cEnd ))
158+ if cells .ndim == 2 :
159+ ngMesh .AddElements (dim = 2 , index = 1 , data = cells , base = 0 )
160+ for bcLabel in range (1 ,plex .getLabelSize (FACE_SETS_LABEL )+ 1 ):
161+ if plex .getStratumSize ("Face Sets" ,bcLabel ) == 0 :
162+ continue
163+ bcIndices = plex .getStratumIS ("Face Sets" ,bcLabel ).indices
164+ for j in bcIndices :
165+ bcIndex = plex .getCone (j )- vStart
166+ if len (bcIndex ) == 2 :
167+ edge = ngm .Element1D ([v + 1 for v in bcIndex ],
168+ index = bcLabel ,
169+ edgenr = bcLabel - 1 )
170+ ngMesh .Add (edge , project_geominfo = geoInfo )
171+
172+ def create3DNetgenMesh (ngMesh , coordinates , plex , geoInfo ):
173+ """
174+ Method used to generate 3D NetgenMeshes
175+
176+ :arg ngMesh: the netgen mesh to be populated
177+ :arg coordinates: vertices coordinates
178+ :arg plex: PETSc DMPlex
179+ :arg geoInfo: geometric information assosciated with the Netgen mesh
180+
181+ """
182+ ngMesh .AddPoints (coordinates )
183+ cStart , cEnd = plex .getHeightStratum (0 )
184+ vStart , _ = plex .getHeightStratum (3 )
185+ # Outside of jitted loop we put all calls to plex
186+ sIndicies = [plex .getCone (i ) for i in range (cStart ,cEnd )]
187+ f1Indicies = np .array ([plex .getCone (s [0 ]) for s in sIndicies ])
188+ f2Indicies = np .array ([plex .getCone (s [1 ]) for s in sIndicies ])
189+ fIndicies = np .hstack ([f1Indicies ,f2Indicies ])
190+
191+ cells_indicies = np .vstack ([np .hstack ([plex .getCone (sIndex [k ])- vStart
192+ for k in range (len (sIndex ))]) for sIndex in fIndicies ])
193+ ngMesh .Add (ngm .FaceDescriptor (bc = 1 ))
194+ ngMesh .Add (ngm .FaceDescriptor (bc = plex .getLabelSize (FACE_SETS_LABEL )+ 1 ))
195+ cells = build3DCells (coordinates , sIndicies ,
196+ cells_indicies , (cStart , cEnd ))
197+ if cells .ndim == 2 :
198+ ngMesh .AddElements (dim = 3 , index = plex .getLabelSize (FACE_SETS_LABEL )+ 1 ,
199+ data = cells , base = 0 )
200+ for bcLabel in range (1 ,plex .getLabelSize (FACE_SETS_LABEL )+ 1 ):
201+ faces = []
202+ if plex .getStratumSize ("Face Sets" ,bcLabel ) == 0 :
203+ continue
204+ bcIndices = plex .getStratumIS ("Face Sets" ,bcLabel ).indices
205+ for j in bcIndices :
206+ sIndex = plex .getCone (j )
207+ if len (sIndex )== 3 :
208+ S = list (itertools .chain .from_iterable ([
209+ list (plex .getCone (sIndex [k ])- vStart ) for k in range (len (sIndex ))]))
210+ face = list (dict .fromkeys (S ))
211+ A = np .array ([coordinates [face [1 ]]- coordinates [face [0 ]],
212+ coordinates [face [2 ]]- coordinates [face [1 ]],
213+ coordinates [face [0 ]]- coordinates [face [2 ]]])
214+ eig = np .linalg .eig (A )[0 ].real
215+ if eig [1 ]* eig [2 ] > 0 :
216+ faces = faces + [face ]
217+ else :
218+ faces = faces + [[face [0 ],face [2 ],face [1 ]]]
219+ ngMesh .Add (ngm .FaceDescriptor (bc = bcLabel , surfnr = bcLabel ))
220+ ngMesh .AddElements (dim = 2 , index = bcLabel ,
221+ data = np .asarray (faces ,dtype = np .int32 ), base = 0 ,
222+ project_geometry = geoInfo )
223+
224+
24225class MeshMapping :
25226 '''
26227 This class creates a mapping between Netgen/NGSolve meshes and PETSc DMPlex
@@ -31,9 +232,10 @@ class MeshMapping:
31232
32233 '''
33234
34- def __init__ (self , mesh = None , comm = None , name = "Default" ):
235+ def __init__ (self , mesh = None , comm = None , geo = None , name = "Default" ):
35236 self .name = name
36237 self .comm = comm if comm is not None else PETSc .COMM_WORLD
238+ self .geo = geo
37239 if isinstance (mesh ,(ngs .comp .Mesh ,ngm .Mesh )):
38240 self .createPETScDMPlex (mesh )
39241 elif isinstance (mesh ,PETSc .DMPlex ):
@@ -58,103 +260,16 @@ def createNGSMesh(self, plex):
58260 self .petscPlex = plex
59261 ngMesh = ngm .Mesh (dim = plex .getCoordinateDim ())
60262 self .ngMesh = ngMesh
263+ self .geoInfo = False
264+ if self .geo :
265+ self .ngMesh .SetGeometry (self .geo )
266+ self .geoInfo = True
61267
62268 coordinates = coordinates .reshape (- 1 ,plex .getDimension ())
63269 if plex .getDimension () == 2 :
64- self .ngMesh .AddPoints (coordinates )
65- cStart ,cEnd = plex .getHeightStratum (0 )
66- vStart , _ = plex .getHeightStratum (2 )
67- cells = []
68- for i in range (cStart ,cEnd ):
69- sIndex = plex .getCone (i )
70- if len (sIndex )== 3 :
71- S = list (itertools .chain .from_iterable ([
72- list (plex .getCone (sIndex [k ])- vStart ) for k in range (len (sIndex ))]))
73- cell = list (dict .fromkeys (S ))
74- A = np .array ([coordinates [cell [1 ]]- coordinates [cell [0 ]],
75- coordinates [cell [2 ]]- coordinates [cell [1 ]]])
76- if np .linalg .det (A ) > 0 :
77- cells = cells + [cell ]
78- else :
79- cells = cells + [[cell [0 ],cell [2 ],cell [1 ]]]
80- else :
81- S = [plex .getCone (sIndex [k ])- vStart for k in list (range (len (sIndex )))]
82- k = 0
83- cell = []
84- while k < len (sIndex ):
85- if S [k ][0 ] == S [k - 1 ][1 ]:
86- cell = cell + [S [k ][0 ]]
87- else :
88- if k == 0 and S [k ][0 ] not in list (S [k + 1 ]):
89- S [- 1 ] = np .array ([S [- 1 ][1 ],S [- 1 ][0 ]])
90- else :
91- S [k ] = np .array ([S [k ][1 ],S [k ][0 ]])
92- cell = cell + [S [k ][0 ]]
93- k = k + 1
94- cells = cells + [cell ]
95- self .ngMesh .Add (ngm .FaceDescriptor (bc = 1 ))
96- cells = np .asarray (cells , dtype = np .int32 )
97- if cells .ndim == 2 :
98- self .ngMesh .AddElements (dim = 2 , index = 1 , data = cells , base = 0 )
99- for bcLabel in range (1 ,plex .getLabelSize (FACE_SETS_LABEL )+ 1 ):
100- if plex .getStratumSize ("Face Sets" ,bcLabel ) == 0 :
101- continue
102- bcIndices = plex .getStratumIS ("Face Sets" ,bcLabel ).indices
103- for j in bcIndices :
104- bcIndex = plex .getCone (j )- vStart
105- if len (bcIndex ) == 2 :
106- edge = ngm .Element1D ([v + 1 for v in bcIndex ],index = bcLabel )
107- self .ngMesh .Add (edge )
270+ create2DNetgenMesh (self .ngMesh , coordinates , plex , self .geoInfo )
108271 elif plex .getDimension () == 3 :
109- self .ngMesh .AddPoints (coordinates )
110- cStart , cEnd = plex .getHeightStratum (0 )
111- vStart , _ = plex .getHeightStratum (3 )
112- cells = []
113- for i in range (cStart ,cEnd ):
114- fIndex = plex .getCone (i )
115- f1 = plex .getCone (fIndex [0 ])
116- f2 = plex .getCone (fIndex [1 ])
117- sIndex = [f1 [0 ],f1 [1 ],f1 [2 ],f2 [0 ],f2 [1 ],f2 [2 ]]
118- if len (fIndex ) == 4 :
119- S = list (itertools .chain .from_iterable ([
120- list (plex .getCone (sIndex [k ])- vStart ) for k in list (range (len (sIndex )))]))
121- cell = list (dict .fromkeys (S ))
122- A = np .array ([coordinates [cell [1 ]]- coordinates [cell [0 ]],
123- coordinates [cell [2 ]]- coordinates [cell [1 ]],
124- coordinates [cell [3 ]]- coordinates [cell [2 ]]])
125- if np .linalg .det (A ) > 0 :
126- cells = cells + [cell ]
127- else :
128- cells = cells + [[cell [0 ],cell [1 ],cell [3 ],cell [2 ]]]
129- #fd = self.ngmesh.Add(ngm.FaceDescriptor(bc=plex.getLabelSize(FACE_SETS_LABEL)+1))
130- self .ngMesh .Add (ngm .FaceDescriptor (bc = plex .getLabelSize (FACE_SETS_LABEL )+ 1 ))
131- cells = np .asarray (cells , dtype = np .int32 )
132- if cells .ndim == 2 :
133- self .ngMesh .AddElements (dim = 3 , index = plex .getLabelSize (FACE_SETS_LABEL )+ 1 ,
134- data = cells , base = 0 )
135- for bcLabel in range (1 ,plex .getLabelSize (FACE_SETS_LABEL )+ 1 ):
136- faces = []
137- if plex .getStratumSize ("Face Sets" ,bcLabel ) == 0 :
138- continue
139- bcIndices = plex .getStratumIS ("Face Sets" ,bcLabel ).indices
140- for j in bcIndices :
141- sIndex = plex .getCone (j )
142- if len (sIndex )== 3 :
143- S = list (itertools .chain .from_iterable ([
144- list (plex .getCone (sIndex [k ])- vStart ) for k in range (len (sIndex ))]))
145- face = list (dict .fromkeys (S ))
146- A = np .array ([coordinates [face [1 ]]- coordinates [face [0 ]],
147- coordinates [face [2 ]]- coordinates [face [1 ]],
148- coordinates [face [0 ]]- coordinates [face [2 ]]])
149- eig = np .linalg .eig (A )[0 ].real
150- if eig [1 ]* eig [2 ] > 0 :
151- faces = faces + [face ]
152- else :
153- faces = faces + [[face [0 ],face [2 ],face [1 ]]]
154- #fd = self.ngmesh.Add(ngm.FaceDescriptor(bc=bcLabel))
155- self .ngMesh .Add (ngm .FaceDescriptor (bc = bcLabel ))
156- self .ngMesh .AddElements (dim = 2 , index = bcLabel ,
157- data = np .asarray (faces ,dtype = np .int32 ), base = 0 )
272+ create3DNetgenMesh (self .ngMesh , coordinates , plex , self .geoInfo )
158273 else :
159274 raise NotImplementedError ("No implementation for dimension greater than 3." )
160275
@@ -170,6 +285,7 @@ def createPETScDMPlex(self, mesh):
170285 else :
171286 self .ngMesh = mesh
172287 comm = self .comm
288+ self .geo = self .ngMesh .GetGeometry ()
173289 if self .ngMesh .dim == 3 :
174290 if comm .rank == 0 :
175291 V = self .ngMesh .Coordinates ()
@@ -180,16 +296,7 @@ def createPETScDMPlex(self, mesh):
180296 surfMesh , dim = True , 2
181297 T = self .ngMesh .Elements2D ().NumPy ()["nodes" ]
182298
183- if Version (np .__version__ ) >= Version ("2.2" ):
184- T = np .trim_zeros (T , "b" , axis = 1 ).astype (np .int32 ) - 1
185- else :
186- T = (
187- np .array (
188- [list (np .trim_zeros (a , "b" )) for a in list (T )],
189- dtype = np .int32 ,
190- )
191- - 1
192- )
299+ T = trim_util (T )
193300
194301 plex = PETSc .DMPlex ().createFromCellList (dim , T , V , comm = comm )
195302 plex .setName (self .name )
0 commit comments