15f34f2dcSJed Brown #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/
2*3458b7b5SJames Wright #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/
35f34f2dcSJed Brown #include <petsc/private/viewercgnsimpl.h>
4*3458b7b5SJames Wright #include <petsc/private/hashseti.h>
55f34f2dcSJed Brown
65f34f2dcSJed Brown #include <pcgnslib.h>
75f34f2dcSJed Brown #include <cgns_io.h>
85f34f2dcSJed Brown
95f34f2dcSJed Brown #if !defined(CGNS_ENUMT)
105f34f2dcSJed Brown #define CGNS_ENUMT(a) a
115f34f2dcSJed Brown #endif
125f34f2dcSJed Brown #if !defined(CGNS_ENUMV)
135f34f2dcSJed Brown #define CGNS_ENUMV(a) a
145f34f2dcSJed Brown #endif
155f34f2dcSJed Brown // Permute plex closure ordering to CGNS
DMPlexCGNSGetPermutation_Internal(DMPolytopeType cell_type,PetscInt closure_size,CGNS_ENUMT (ElementType_t)* element_type,const int ** perm)16d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCGNSGetPermutation_Internal(DMPolytopeType cell_type, PetscInt closure_size, CGNS_ENUMT(ElementType_t) * element_type, const int **perm)
17d71ae5a4SJacob Faibussowitsch {
18472b9844SJames Wright CGNS_ENUMT(ElementType_t) element_type_tmp;
19472b9844SJames Wright
20472b9844SJames Wright // https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid
215f34f2dcSJed Brown static const int bar_2[2] = {0, 1};
225f34f2dcSJed Brown static const int bar_3[3] = {1, 2, 0};
235f34f2dcSJed Brown static const int bar_4[4] = {2, 3, 0, 1};
245f34f2dcSJed Brown static const int bar_5[5] = {3, 4, 0, 1, 2};
255f34f2dcSJed Brown static const int tri_3[3] = {0, 1, 2};
265f34f2dcSJed Brown static const int tri_6[6] = {3, 4, 5, 0, 1, 2};
275f34f2dcSJed Brown static const int tri_10[10] = {7, 8, 9, 1, 2, 3, 4, 5, 6, 0};
285f34f2dcSJed Brown static const int quad_4[4] = {0, 1, 2, 3};
295f34f2dcSJed Brown static const int quad_9[9] = {
305f34f2dcSJed Brown 5, 6, 7, 8, // vertices
315f34f2dcSJed Brown 1, 2, 3, 4, // edges
325f34f2dcSJed Brown 0, // center
335f34f2dcSJed Brown };
345f34f2dcSJed Brown static const int quad_16[] = {
355f34f2dcSJed Brown 12, 13, 14, 15, // vertices
365f34f2dcSJed Brown 4, 5, 6, 7, 8, 9, 10, 11, // edges
375f34f2dcSJed Brown 0, 1, 3, 2, // centers
385f34f2dcSJed Brown };
395f34f2dcSJed Brown static const int quad_25[] = {
405f34f2dcSJed Brown 21, 22, 23, 24, // vertices
415f34f2dcSJed Brown 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, // edges
425f34f2dcSJed Brown 0, 1, 2, 5, 8, 7, 6, 3, 4, // centers
435f34f2dcSJed Brown };
445f34f2dcSJed Brown static const int tetra_4[4] = {0, 2, 1, 3};
455f34f2dcSJed Brown static const int tetra_10[10] = {6, 8, 7, 9, 2, 1, 0, 3, 5, 4};
465f34f2dcSJed Brown static const int tetra_20[20] = {
475f34f2dcSJed Brown 16, 18, 17, 19, // vertices
485f34f2dcSJed Brown 9, 8, 7, 6, 5, 4, // bottom edges
495f34f2dcSJed Brown 10, 11, 14, 15, 13, 12, // side edges
505f34f2dcSJed Brown 0, 2, 3, 1, // faces
515f34f2dcSJed Brown };
525f34f2dcSJed Brown static const int hexa_8[8] = {0, 3, 2, 1, 4, 5, 6, 7};
535f34f2dcSJed Brown static const int hexa_27[27] = {
545f34f2dcSJed Brown 19, 22, 21, 20, 23, 24, 25, 26, // vertices
555f34f2dcSJed Brown 10, 9, 8, 7, // bottom edges
565f34f2dcSJed Brown 16, 15, 18, 17, // mid edges
575f34f2dcSJed Brown 11, 12, 13, 14, // top edges
585f34f2dcSJed Brown 1, 3, 5, 4, 6, 2, // faces
595f34f2dcSJed Brown 0, // center
605f34f2dcSJed Brown };
619371c9d4SSatish Balay static const int hexa_64[64] = {
629371c9d4SSatish Balay // debug with $PETSC_ARCH/tests/dm/impls/plex/tests/ex49 -dm_plex_simplex 0 -dm_plex_dim 3 -dm_plex_box_faces 1,1,1 -dm_coord_petscspace_degree 3
635f34f2dcSJed Brown 56, 59, 58, 57, 60, 61, 62, 63, // vertices
645f34f2dcSJed Brown 39, 38, 37, 36, 35, 34, 33, 32, // bottom edges
655f34f2dcSJed Brown 51, 50, 48, 49, 52, 53, 55, 54, // mid edges; Paraview needs edge 21-22 swapped with 23-24
665f34f2dcSJed Brown 40, 41, 42, 43, 44, 45, 46, 47, // top edges
675f34f2dcSJed Brown 8, 10, 11, 9, // z-minus face
685f34f2dcSJed Brown 16, 17, 19, 18, // y-minus face
695f34f2dcSJed Brown 24, 25, 27, 26, // x-plus face
705f34f2dcSJed Brown 20, 21, 23, 22, // y-plus face
715f34f2dcSJed Brown 30, 28, 29, 31, // x-minus face
725f34f2dcSJed Brown 12, 13, 15, 14, // z-plus face
735f34f2dcSJed Brown 0, 1, 3, 2, 4, 5, 7, 6, // center
745f34f2dcSJed Brown };
755f34f2dcSJed Brown
765f34f2dcSJed Brown PetscFunctionBegin;
77472b9844SJames Wright element_type_tmp = CGNS_ENUMV(ElementTypeNull);
785f34f2dcSJed Brown *perm = NULL;
795f34f2dcSJed Brown switch (cell_type) {
805f34f2dcSJed Brown case DM_POLYTOPE_SEGMENT:
815f34f2dcSJed Brown switch (closure_size) {
82d71ae5a4SJacob Faibussowitsch case 2:
83472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_2);
84d71ae5a4SJacob Faibussowitsch *perm = bar_2;
85b30057acSJames Wright break;
86d71ae5a4SJacob Faibussowitsch case 3:
87472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_3);
88d71ae5a4SJacob Faibussowitsch *perm = bar_3;
89b30057acSJames Wright break;
905f34f2dcSJed Brown case 4:
91472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_4);
925f34f2dcSJed Brown *perm = bar_4;
935f34f2dcSJed Brown break;
945f34f2dcSJed Brown case 5:
95472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_5);
965f34f2dcSJed Brown *perm = bar_5;
975f34f2dcSJed Brown break;
98d71ae5a4SJacob Faibussowitsch default:
99d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1005f34f2dcSJed Brown }
1015f34f2dcSJed Brown break;
1025f34f2dcSJed Brown case DM_POLYTOPE_TRIANGLE:
1035f34f2dcSJed Brown switch (closure_size) {
1045f34f2dcSJed Brown case 3:
105472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_3);
1065f34f2dcSJed Brown *perm = tri_3;
1075f34f2dcSJed Brown break;
1085f34f2dcSJed Brown case 6:
109472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_6);
1105f34f2dcSJed Brown *perm = tri_6;
1115f34f2dcSJed Brown break;
1125f34f2dcSJed Brown case 10:
113472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_10);
1145f34f2dcSJed Brown *perm = tri_10;
1155f34f2dcSJed Brown break;
116d71ae5a4SJacob Faibussowitsch default:
117d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1185f34f2dcSJed Brown }
1195f34f2dcSJed Brown break;
1205f34f2dcSJed Brown case DM_POLYTOPE_QUADRILATERAL:
1215f34f2dcSJed Brown switch (closure_size) {
1225f34f2dcSJed Brown case 4:
123472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_4);
1245f34f2dcSJed Brown *perm = quad_4;
1255f34f2dcSJed Brown break;
1265f34f2dcSJed Brown case 9:
127472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_9);
1285f34f2dcSJed Brown *perm = quad_9;
1295f34f2dcSJed Brown break;
1305f34f2dcSJed Brown case 16:
131472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_16);
1325f34f2dcSJed Brown *perm = quad_16;
1335f34f2dcSJed Brown break;
1345f34f2dcSJed Brown case 25:
135472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_25);
1365f34f2dcSJed Brown *perm = quad_25;
1375f34f2dcSJed Brown break;
138d71ae5a4SJacob Faibussowitsch default:
139d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1405f34f2dcSJed Brown }
1415f34f2dcSJed Brown break;
1425f34f2dcSJed Brown case DM_POLYTOPE_TETRAHEDRON:
1435f34f2dcSJed Brown switch (closure_size) {
1445f34f2dcSJed Brown case 4:
145472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_4);
1465f34f2dcSJed Brown *perm = tetra_4;
1475f34f2dcSJed Brown break;
1485f34f2dcSJed Brown case 10:
149472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_10);
1505f34f2dcSJed Brown *perm = tetra_10;
1515f34f2dcSJed Brown break;
1525f34f2dcSJed Brown case 20:
153472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_20);
1545f34f2dcSJed Brown *perm = tetra_20;
1555f34f2dcSJed Brown break;
156d71ae5a4SJacob Faibussowitsch default:
157d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1585f34f2dcSJed Brown }
1595f34f2dcSJed Brown break;
1605f34f2dcSJed Brown case DM_POLYTOPE_HEXAHEDRON:
1615f34f2dcSJed Brown switch (closure_size) {
1625f34f2dcSJed Brown case 8:
163472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_8);
1645f34f2dcSJed Brown *perm = hexa_8;
1655f34f2dcSJed Brown break;
1665f34f2dcSJed Brown case 27:
167472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_27);
1685f34f2dcSJed Brown *perm = hexa_27;
1695f34f2dcSJed Brown break;
1705f34f2dcSJed Brown case 64:
171472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_64);
1725f34f2dcSJed Brown *perm = hexa_64;
1735f34f2dcSJed Brown break;
174d71ae5a4SJacob Faibussowitsch default:
175d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1765f34f2dcSJed Brown }
1775f34f2dcSJed Brown break;
178d71ae5a4SJacob Faibussowitsch default:
179d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size);
1805f34f2dcSJed Brown }
181472b9844SJames Wright if (element_type) *element_type = element_type_tmp;
182472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
183472b9844SJames Wright }
184472b9844SJames Wright
185472b9844SJames Wright /*
186472b9844SJames Wright Input Parameters:
187472b9844SJames Wright + cellType - The CGNS-defined element type
188472b9844SJames Wright
189472b9844SJames Wright Output Parameters:
190472b9844SJames Wright + dmcelltype - The equivalent DMPolytopeType for the cellType
191472b9844SJames Wright . numCorners - Number of corners of the polytope
192472b9844SJames Wright - dim - The topological dimension of the polytope
193472b9844SJames Wright
194472b9844SJames Wright CGNS elements defined in: https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid
195472b9844SJames Wright */
CGNSElementTypeGetTopologyInfo(CGNS_ENUMT (ElementType_t)cellType,DMPolytopeType * dmcelltype,PetscInt * numCorners,PetscInt * dim)196472b9844SJames Wright static inline PetscErrorCode CGNSElementTypeGetTopologyInfo(CGNS_ENUMT(ElementType_t) cellType, DMPolytopeType *dmcelltype, PetscInt *numCorners, PetscInt *dim)
197472b9844SJames Wright {
198472b9844SJames Wright DMPolytopeType _dmcelltype;
199472b9844SJames Wright
200b30057acSJames Wright PetscFunctionBegin;
201472b9844SJames Wright switch (cellType) {
202472b9844SJames Wright case CGNS_ENUMV(BAR_2):
203472b9844SJames Wright case CGNS_ENUMV(BAR_3):
204472b9844SJames Wright case CGNS_ENUMV(BAR_4):
205472b9844SJames Wright case CGNS_ENUMV(BAR_5):
206472b9844SJames Wright _dmcelltype = DM_POLYTOPE_SEGMENT;
207472b9844SJames Wright break;
208472b9844SJames Wright case CGNS_ENUMV(TRI_3):
209472b9844SJames Wright case CGNS_ENUMV(TRI_6):
210472b9844SJames Wright case CGNS_ENUMV(TRI_9):
211472b9844SJames Wright case CGNS_ENUMV(TRI_10):
212472b9844SJames Wright case CGNS_ENUMV(TRI_12):
213472b9844SJames Wright case CGNS_ENUMV(TRI_15):
214472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TRIANGLE;
215472b9844SJames Wright break;
216472b9844SJames Wright case CGNS_ENUMV(QUAD_4):
217472b9844SJames Wright case CGNS_ENUMV(QUAD_8):
218472b9844SJames Wright case CGNS_ENUMV(QUAD_9):
219472b9844SJames Wright case CGNS_ENUMV(QUAD_12):
220472b9844SJames Wright case CGNS_ENUMV(QUAD_16):
221472b9844SJames Wright case CGNS_ENUMV(QUAD_P4_16):
222472b9844SJames Wright case CGNS_ENUMV(QUAD_25):
223472b9844SJames Wright _dmcelltype = DM_POLYTOPE_QUADRILATERAL;
224472b9844SJames Wright break;
225472b9844SJames Wright case CGNS_ENUMV(TETRA_4):
226472b9844SJames Wright case CGNS_ENUMV(TETRA_10):
227472b9844SJames Wright case CGNS_ENUMV(TETRA_16):
228472b9844SJames Wright case CGNS_ENUMV(TETRA_20):
229472b9844SJames Wright case CGNS_ENUMV(TETRA_22):
230472b9844SJames Wright case CGNS_ENUMV(TETRA_34):
231472b9844SJames Wright case CGNS_ENUMV(TETRA_35):
232472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TETRAHEDRON;
233472b9844SJames Wright break;
234472b9844SJames Wright case CGNS_ENUMV(PYRA_5):
235472b9844SJames Wright case CGNS_ENUMV(PYRA_13):
236472b9844SJames Wright case CGNS_ENUMV(PYRA_14):
237472b9844SJames Wright case CGNS_ENUMV(PYRA_21):
238472b9844SJames Wright case CGNS_ENUMV(PYRA_29):
239472b9844SJames Wright case CGNS_ENUMV(PYRA_P4_29):
240472b9844SJames Wright case CGNS_ENUMV(PYRA_30):
241472b9844SJames Wright case CGNS_ENUMV(PYRA_50):
242472b9844SJames Wright case CGNS_ENUMV(PYRA_55):
243472b9844SJames Wright _dmcelltype = DM_POLYTOPE_PYRAMID;
244472b9844SJames Wright break;
245472b9844SJames Wright case CGNS_ENUMV(PENTA_6):
246472b9844SJames Wright case CGNS_ENUMV(PENTA_15):
247472b9844SJames Wright case CGNS_ENUMV(PENTA_18):
248472b9844SJames Wright case CGNS_ENUMV(PENTA_24):
249472b9844SJames Wright case CGNS_ENUMV(PENTA_33):
250472b9844SJames Wright case CGNS_ENUMV(PENTA_38):
251472b9844SJames Wright case CGNS_ENUMV(PENTA_40):
252472b9844SJames Wright case CGNS_ENUMV(PENTA_66):
253472b9844SJames Wright case CGNS_ENUMV(PENTA_75):
254472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TRI_PRISM;
255472b9844SJames Wright break;
256472b9844SJames Wright case CGNS_ENUMV(HEXA_8):
257472b9844SJames Wright case CGNS_ENUMV(HEXA_20):
258472b9844SJames Wright case CGNS_ENUMV(HEXA_27):
259472b9844SJames Wright case CGNS_ENUMV(HEXA_32):
260472b9844SJames Wright case CGNS_ENUMV(HEXA_44):
261472b9844SJames Wright case CGNS_ENUMV(HEXA_56):
262472b9844SJames Wright case CGNS_ENUMV(HEXA_64):
263472b9844SJames Wright case CGNS_ENUMV(HEXA_98):
264472b9844SJames Wright case CGNS_ENUMV(HEXA_125):
265472b9844SJames Wright _dmcelltype = DM_POLYTOPE_HEXAHEDRON;
266472b9844SJames Wright break;
267472b9844SJames Wright case CGNS_ENUMV(MIXED):
268472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: MIXED");
269472b9844SJames Wright default:
270472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: %d", (int)cellType);
271472b9844SJames Wright }
272472b9844SJames Wright
273472b9844SJames Wright if (dmcelltype) *dmcelltype = _dmcelltype;
274472b9844SJames Wright if (numCorners) *numCorners = DMPolytopeTypeGetNumVertices(_dmcelltype);
275472b9844SJames Wright if (dim) *dim = DMPolytopeTypeGetDim(_dmcelltype);
276472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
277472b9844SJames Wright }
278472b9844SJames Wright
279472b9844SJames Wright /*
280472b9844SJames Wright Input Parameters:
281472b9844SJames Wright + cellType - The CGNS-defined cell type
282472b9844SJames Wright
283472b9844SJames Wright Output Parameters:
284472b9844SJames Wright + numClosure - Number of nodes that define the function space on the cell
285472b9844SJames Wright - pOrder - The polynomial order of the cell
286472b9844SJames Wright
287472b9844SJames Wright CGNS elements defined in: https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid
288472b9844SJames Wright
289472b9844SJames Wright Note: we only support "full" elements, ie. not seredipity elements
290472b9844SJames Wright */
CGNSElementTypeGetDiscretizationInfo(CGNS_ENUMT (ElementType_t)cellType,PetscInt * numClosure,PetscInt * pOrder)291472b9844SJames Wright static inline PetscErrorCode CGNSElementTypeGetDiscretizationInfo(CGNS_ENUMT(ElementType_t) cellType, PetscInt *numClosure, PetscInt *pOrder)
292472b9844SJames Wright {
293472b9844SJames Wright PetscInt _numClosure, _pOrder;
294472b9844SJames Wright
295b30057acSJames Wright PetscFunctionBegin;
296472b9844SJames Wright switch (cellType) {
297472b9844SJames Wright case CGNS_ENUMV(BAR_2):
298472b9844SJames Wright _numClosure = 2;
299472b9844SJames Wright _pOrder = 1;
300472b9844SJames Wright break;
301472b9844SJames Wright case CGNS_ENUMV(BAR_3):
302472b9844SJames Wright _numClosure = 3;
303472b9844SJames Wright _pOrder = 2;
304472b9844SJames Wright break;
305472b9844SJames Wright case CGNS_ENUMV(BAR_4):
306472b9844SJames Wright _numClosure = 4;
307472b9844SJames Wright _pOrder = 3;
308472b9844SJames Wright break;
309472b9844SJames Wright case CGNS_ENUMV(BAR_5):
310472b9844SJames Wright _numClosure = 5;
311472b9844SJames Wright _pOrder = 4;
312472b9844SJames Wright break;
313472b9844SJames Wright case CGNS_ENUMV(TRI_3):
314472b9844SJames Wright _numClosure = 3;
315472b9844SJames Wright _pOrder = 1;
316472b9844SJames Wright break;
317472b9844SJames Wright case CGNS_ENUMV(TRI_6):
318472b9844SJames Wright _numClosure = 6;
319472b9844SJames Wright _pOrder = 2;
320472b9844SJames Wright break;
321472b9844SJames Wright case CGNS_ENUMV(TRI_10):
322472b9844SJames Wright _numClosure = 10;
323472b9844SJames Wright _pOrder = 3;
324472b9844SJames Wright break;
325472b9844SJames Wright case CGNS_ENUMV(TRI_15):
326472b9844SJames Wright _numClosure = 15;
327472b9844SJames Wright _pOrder = 4;
328472b9844SJames Wright break;
329472b9844SJames Wright case CGNS_ENUMV(QUAD_4):
330472b9844SJames Wright _numClosure = 4;
331472b9844SJames Wright _pOrder = 1;
332472b9844SJames Wright break;
333472b9844SJames Wright case CGNS_ENUMV(QUAD_9):
334472b9844SJames Wright _numClosure = 9;
335472b9844SJames Wright _pOrder = 2;
336472b9844SJames Wright break;
337472b9844SJames Wright case CGNS_ENUMV(QUAD_16):
338472b9844SJames Wright _numClosure = 16;
339472b9844SJames Wright _pOrder = 3;
340472b9844SJames Wright break;
341472b9844SJames Wright case CGNS_ENUMV(QUAD_25):
342472b9844SJames Wright _numClosure = 25;
343472b9844SJames Wright _pOrder = 4;
344472b9844SJames Wright break;
345472b9844SJames Wright case CGNS_ENUMV(TETRA_4):
346472b9844SJames Wright _numClosure = 4;
347472b9844SJames Wright _pOrder = 1;
348472b9844SJames Wright break;
349472b9844SJames Wright case CGNS_ENUMV(TETRA_10):
350472b9844SJames Wright _numClosure = 10;
351472b9844SJames Wright _pOrder = 2;
352472b9844SJames Wright break;
353472b9844SJames Wright case CGNS_ENUMV(TETRA_20):
354472b9844SJames Wright _numClosure = 20;
355472b9844SJames Wright _pOrder = 3;
356472b9844SJames Wright break;
357472b9844SJames Wright case CGNS_ENUMV(TETRA_35):
358472b9844SJames Wright _numClosure = 35;
359472b9844SJames Wright _pOrder = 4;
360472b9844SJames Wright break;
361472b9844SJames Wright case CGNS_ENUMV(PYRA_5):
362472b9844SJames Wright _numClosure = 5;
363472b9844SJames Wright _pOrder = 1;
364472b9844SJames Wright break;
365472b9844SJames Wright case CGNS_ENUMV(PYRA_14):
366472b9844SJames Wright _numClosure = 14;
367472b9844SJames Wright _pOrder = 2;
368472b9844SJames Wright break;
369472b9844SJames Wright case CGNS_ENUMV(PYRA_30):
370472b9844SJames Wright _numClosure = 30;
371472b9844SJames Wright _pOrder = 3;
372472b9844SJames Wright break;
373472b9844SJames Wright case CGNS_ENUMV(PYRA_55):
374472b9844SJames Wright _numClosure = 55;
375472b9844SJames Wright _pOrder = 4;
376472b9844SJames Wright break;
377472b9844SJames Wright case CGNS_ENUMV(PENTA_6):
378472b9844SJames Wright _numClosure = 6;
379472b9844SJames Wright _pOrder = 1;
380472b9844SJames Wright break;
381472b9844SJames Wright case CGNS_ENUMV(PENTA_18):
382472b9844SJames Wright _numClosure = 18;
383472b9844SJames Wright _pOrder = 2;
384472b9844SJames Wright break;
385472b9844SJames Wright case CGNS_ENUMV(PENTA_40):
386472b9844SJames Wright _numClosure = 40;
387472b9844SJames Wright _pOrder = 3;
388472b9844SJames Wright break;
389472b9844SJames Wright case CGNS_ENUMV(PENTA_75):
390472b9844SJames Wright _numClosure = 75;
391472b9844SJames Wright _pOrder = 4;
392472b9844SJames Wright break;
393472b9844SJames Wright case CGNS_ENUMV(HEXA_8):
394472b9844SJames Wright _numClosure = 8;
395472b9844SJames Wright _pOrder = 1;
396472b9844SJames Wright break;
397472b9844SJames Wright case CGNS_ENUMV(HEXA_27):
398472b9844SJames Wright _numClosure = 27;
399472b9844SJames Wright _pOrder = 2;
400472b9844SJames Wright break;
401472b9844SJames Wright case CGNS_ENUMV(HEXA_64):
402472b9844SJames Wright _numClosure = 64;
403472b9844SJames Wright _pOrder = 3;
404472b9844SJames Wright break;
405472b9844SJames Wright case CGNS_ENUMV(HEXA_125):
406472b9844SJames Wright _numClosure = 125;
407472b9844SJames Wright _pOrder = 4;
408472b9844SJames Wright break;
409472b9844SJames Wright case CGNS_ENUMV(MIXED):
410472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: MIXED");
411472b9844SJames Wright default:
412472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported or Invalid cell type %d", (int)cellType);
413472b9844SJames Wright }
414472b9844SJames Wright if (numClosure) *numClosure = _numClosure;
415472b9844SJames Wright if (pOrder) *pOrder = _pOrder;
416472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
417472b9844SJames Wright }
418472b9844SJames Wright
PetscCGNSDataType(PetscDataType pd,CGNS_ENUMT (DataType_t)* cd)419472b9844SJames Wright static PetscErrorCode PetscCGNSDataType(PetscDataType pd, CGNS_ENUMT(DataType_t) * cd)
420472b9844SJames Wright {
421472b9844SJames Wright PetscFunctionBegin;
422472b9844SJames Wright switch (pd) {
423472b9844SJames Wright case PETSC_FLOAT:
424472b9844SJames Wright *cd = CGNS_ENUMV(RealSingle);
425472b9844SJames Wright break;
426472b9844SJames Wright case PETSC_DOUBLE:
427472b9844SJames Wright *cd = CGNS_ENUMV(RealDouble);
428472b9844SJames Wright break;
429472b9844SJames Wright case PETSC_COMPLEX:
430472b9844SJames Wright *cd = CGNS_ENUMV(ComplexDouble);
431472b9844SJames Wright break;
432472b9844SJames Wright default:
433472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Data type %s", PetscDataTypes[pd]);
434472b9844SJames Wright }
435472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
436472b9844SJames Wright }
437472b9844SJames Wright
DMPlexCreateCGNSFromFile_Internal(MPI_Comm comm,const char filename[],PetscBool interpolate,DM * dm)438472b9844SJames Wright PetscErrorCode DMPlexCreateCGNSFromFile_Internal(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
439472b9844SJames Wright {
440472b9844SJames Wright int cgid = -1;
441472b9844SJames Wright PetscBool use_parallel_viewer = PETSC_FALSE;
442472b9844SJames Wright
443472b9844SJames Wright PetscFunctionBegin;
444472b9844SJames Wright PetscAssertPointer(filename, 2);
4455582b114SJames Wright PetscCall(PetscViewerCGNSRegisterLogEvents_Internal());
446472b9844SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_parallel", &use_parallel_viewer, NULL));
447472b9844SJames Wright
448472b9844SJames Wright if (use_parallel_viewer) {
449472b9844SJames Wright PetscCallCGNS(cgp_mpi_comm(comm));
4504c155f28SJames Wright PetscCallCGNSOpen(cgp_open(filename, CG_MODE_READ, &cgid), 0, 0);
451472b9844SJames Wright PetscCheck(cgid > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "cgp_open(\"%s\",...) did not return a valid file ID", filename);
452472b9844SJames Wright PetscCall(DMPlexCreateCGNS(comm, cgid, interpolate, dm));
4534c155f28SJames Wright PetscCallCGNSClose(cgp_close(cgid), 0, 0);
454472b9844SJames Wright } else {
4554c155f28SJames Wright PetscCallCGNSOpen(cg_open(filename, CG_MODE_READ, &cgid), 0, 0);
456472b9844SJames Wright PetscCheck(cgid > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "cg_open(\"%s\",...) did not return a valid file ID", filename);
457472b9844SJames Wright PetscCall(DMPlexCreateCGNS(comm, cgid, interpolate, dm));
4584c155f28SJames Wright PetscCallCGNSClose(cg_close(cgid), 0, 0);
459472b9844SJames Wright }
460472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
461472b9844SJames Wright }
462472b9844SJames Wright
DMPlexCreateCGNS_Internal_Serial(MPI_Comm comm,PetscInt cgid,PetscBool interpolate,DM * dm)463472b9844SJames Wright PetscErrorCode DMPlexCreateCGNS_Internal_Serial(MPI_Comm comm, PetscInt cgid, PetscBool interpolate, DM *dm)
464472b9844SJames Wright {
465472b9844SJames Wright PetscMPIInt num_proc, rank;
466472b9844SJames Wright DM cdm;
467472b9844SJames Wright DMLabel label;
468472b9844SJames Wright PetscSection coordSection;
469472b9844SJames Wright Vec coordinates;
470472b9844SJames Wright PetscScalar *coords;
471472b9844SJames Wright PetscInt *cellStart, *vertStart, v;
472472b9844SJames Wright PetscInt labelIdRange[2], labelId;
473472b9844SJames Wright /* Read from file */
474472b9844SJames Wright char basename[CGIO_MAX_NAME_LENGTH + 1];
475472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1];
476472b9844SJames Wright int dim = 0, physDim = 0, coordDim = 0, numVertices = 0, numCells = 0;
477472b9844SJames Wright int nzones = 0;
478472b9844SJames Wright const int B = 1; // Only support single base
479472b9844SJames Wright
480472b9844SJames Wright PetscFunctionBegin;
481472b9844SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank));
482472b9844SJames Wright PetscCallMPI(MPI_Comm_size(comm, &num_proc));
483472b9844SJames Wright PetscCall(DMCreate(comm, dm));
484472b9844SJames Wright PetscCall(DMSetType(*dm, DMPLEX));
485472b9844SJames Wright
486472b9844SJames Wright /* Open CGNS II file and read basic information on rank 0, then broadcast to all processors */
487472b9844SJames Wright if (rank == 0) {
488472b9844SJames Wright int nbases, z;
489472b9844SJames Wright
4904c155f28SJames Wright PetscCallCGNSRead(cg_nbases(cgid, &nbases), *dm, 0);
491472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases);
4924c155f28SJames Wright PetscCallCGNSRead(cg_base_read(cgid, B, basename, &dim, &physDim), *dm, 0);
4934c155f28SJames Wright PetscCallCGNSRead(cg_nzones(cgid, B, &nzones), *dm, 0);
494472b9844SJames Wright PetscCall(PetscCalloc2(nzones + 1, &cellStart, nzones + 1, &vertStart));
495472b9844SJames Wright for (z = 1; z <= nzones; ++z) {
496472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */
497472b9844SJames Wright
4984c155f28SJames Wright PetscCallCGNSRead(cg_zone_read(cgid, B, z, buffer, sizes), *dm, 0);
499472b9844SJames Wright numVertices += sizes[0];
500472b9844SJames Wright numCells += sizes[1];
501472b9844SJames Wright cellStart[z] += sizes[1] + cellStart[z - 1];
502472b9844SJames Wright vertStart[z] += sizes[0] + vertStart[z - 1];
503472b9844SJames Wright }
504472b9844SJames Wright for (z = 1; z <= nzones; ++z) vertStart[z] += numCells;
505472b9844SJames Wright coordDim = dim;
506472b9844SJames Wright }
507472b9844SJames Wright PetscCallMPI(MPI_Bcast(basename, CGIO_MAX_NAME_LENGTH + 1, MPI_CHAR, 0, comm));
508472b9844SJames Wright PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
509472b9844SJames Wright PetscCallMPI(MPI_Bcast(&coordDim, 1, MPI_INT, 0, comm));
510472b9844SJames Wright PetscCallMPI(MPI_Bcast(&nzones, 1, MPI_INT, 0, comm));
511472b9844SJames Wright
512472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)*dm, basename));
513472b9844SJames Wright PetscCall(DMSetDimension(*dm, dim));
514472b9844SJames Wright PetscCall(DMCreateLabel(*dm, "celltype"));
515472b9844SJames Wright PetscCall(DMPlexSetChart(*dm, 0, numCells + numVertices));
516472b9844SJames Wright
517472b9844SJames Wright /* Read zone information */
518472b9844SJames Wright if (rank == 0) {
519472b9844SJames Wright int z, c, c_loc;
520472b9844SJames Wright
521472b9844SJames Wright /* Read the cell set connectivity table and build mesh topology
522472b9844SJames Wright CGNS standard requires that cells in a zone be numbered sequentially and be pairwise disjoint. */
523472b9844SJames Wright /* First set sizes */
524472b9844SJames Wright for (z = 1, c = 0; z <= nzones; ++z) {
525472b9844SJames Wright CGNS_ENUMT(ZoneType_t) zonetype;
526472b9844SJames Wright int nsections;
527472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType;
528472b9844SJames Wright cgsize_t start, end;
529472b9844SJames Wright int nbndry, parentFlag;
530472b9844SJames Wright PetscInt numCorners, pOrder;
531472b9844SJames Wright DMPolytopeType ctype;
532472b9844SJames Wright const int S = 1; // Only support single section
533472b9844SJames Wright
5344c155f28SJames Wright PetscCallCGNSRead(cg_zone_type(cgid, B, z, &zonetype), *dm, 0);
535472b9844SJames Wright PetscCheck(zonetype != CGNS_ENUMV(Structured), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can only handle Unstructured zones for CGNS");
5364c155f28SJames Wright PetscCallCGNSRead(cg_nsections(cgid, B, z, &nsections), *dm, 0);
537472b9844SJames Wright PetscCheck(nsections <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single section, not %d", nsections);
5384c155f28SJames Wright PetscCallCGNSRead(cg_section_read(cgid, B, z, S, buffer, &cellType, &start, &end, &nbndry, &parentFlag), *dm, 0);
539472b9844SJames Wright if (cellType == CGNS_ENUMV(MIXED)) {
540472b9844SJames Wright cgsize_t elementDataSize, *elements;
541472b9844SJames Wright PetscInt off;
542472b9844SJames Wright
5434c155f28SJames Wright PetscCallCGNSRead(cg_ElementDataSize(cgid, B, z, S, &elementDataSize), *dm, 0);
544472b9844SJames Wright PetscCall(PetscMalloc1(elementDataSize, &elements));
5454c155f28SJames Wright PetscCallCGNSReadData(cg_poly_elements_read(cgid, B, z, S, elements, NULL, NULL), *dm, 0);
546472b9844SJames Wright for (c_loc = start, off = 0; c_loc <= end; ++c_loc, ++c) {
547ca328833SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo((CGNS_ENUMT(ElementType_t))elements[off], &ctype, &numCorners, NULL));
548ca328833SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo((CGNS_ENUMT(ElementType_t))elements[off], NULL, &pOrder));
549472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder);
550472b9844SJames Wright PetscCall(DMPlexSetConeSize(*dm, c, numCorners));
551472b9844SJames Wright PetscCall(DMPlexSetCellType(*dm, c, ctype));
552472b9844SJames Wright off += numCorners + 1;
553472b9844SJames Wright }
554472b9844SJames Wright PetscCall(PetscFree(elements));
555472b9844SJames Wright } else {
556472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, &ctype, &numCorners, NULL));
557472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, NULL, &pOrder));
558472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder);
559472b9844SJames Wright for (c_loc = start; c_loc <= end; ++c_loc, ++c) {
560472b9844SJames Wright PetscCall(DMPlexSetConeSize(*dm, c, numCorners));
561472b9844SJames Wright PetscCall(DMPlexSetCellType(*dm, c, ctype));
562472b9844SJames Wright }
563472b9844SJames Wright }
564472b9844SJames Wright }
565472b9844SJames Wright for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
566472b9844SJames Wright }
567472b9844SJames Wright
568472b9844SJames Wright PetscCall(DMSetUp(*dm));
569472b9844SJames Wright
570472b9844SJames Wright PetscCall(DMCreateLabel(*dm, "zone"));
571472b9844SJames Wright if (rank == 0) {
572472b9844SJames Wright int z, c, c_loc, v_loc;
573472b9844SJames Wright
574472b9844SJames Wright PetscCall(DMGetLabel(*dm, "zone", &label));
575472b9844SJames Wright for (z = 1, c = 0; z <= nzones; ++z) {
576472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType;
577472b9844SJames Wright cgsize_t elementDataSize, *elements, start, end;
578472b9844SJames Wright int nbndry, parentFlag;
579472b9844SJames Wright PetscInt *cone, numc, numCorners, maxCorners = 27, pOrder;
580472b9844SJames Wright const int S = 1; // Only support single section
581472b9844SJames Wright
5824c155f28SJames Wright PetscCallCGNSRead(cg_section_read(cgid, B, z, S, buffer, &cellType, &start, &end, &nbndry, &parentFlag), *dm, 0);
583472b9844SJames Wright numc = end - start;
5844c155f28SJames Wright PetscCallCGNSRead(cg_ElementDataSize(cgid, B, z, S, &elementDataSize), *dm, 0);
585472b9844SJames Wright PetscCall(PetscMalloc2(elementDataSize, &elements, maxCorners, &cone));
5864c155f28SJames Wright PetscCallCGNSReadData(cg_poly_elements_read(cgid, B, z, S, elements, NULL, NULL), *dm, 0);
587472b9844SJames Wright if (cellType == CGNS_ENUMV(MIXED)) {
588472b9844SJames Wright /* CGNS uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */
589472b9844SJames Wright for (c_loc = 0, v = 0; c_loc <= numc; ++c_loc, ++c) {
590ca328833SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo((CGNS_ENUMT(ElementType_t))elements[v], NULL, &numCorners, NULL));
591ca328833SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo((CGNS_ENUMT(ElementType_t))elements[v], NULL, &pOrder));
592472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder);
593472b9844SJames Wright ++v;
594472b9844SJames Wright for (v_loc = 0; v_loc < numCorners; ++v_loc, ++v) cone[v_loc] = elements[v] + numCells - 1;
595472b9844SJames Wright PetscCall(DMPlexReorderCell(*dm, c, cone));
596472b9844SJames Wright PetscCall(DMPlexSetCone(*dm, c, cone));
597472b9844SJames Wright PetscCall(DMLabelSetValue(label, c, z));
598472b9844SJames Wright }
599472b9844SJames Wright } else {
600472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, NULL, &numCorners, NULL));
601472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, NULL, &pOrder));
602472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder);
603472b9844SJames Wright /* CGNS uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */
604472b9844SJames Wright for (c_loc = 0, v = 0; c_loc <= numc; ++c_loc, ++c) {
605472b9844SJames Wright for (v_loc = 0; v_loc < numCorners; ++v_loc, ++v) cone[v_loc] = elements[v] + numCells - 1;
606472b9844SJames Wright PetscCall(DMPlexReorderCell(*dm, c, cone));
607472b9844SJames Wright PetscCall(DMPlexSetCone(*dm, c, cone));
608472b9844SJames Wright PetscCall(DMLabelSetValue(label, c, z));
609472b9844SJames Wright }
610472b9844SJames Wright }
611472b9844SJames Wright PetscCall(PetscFree2(elements, cone));
612472b9844SJames Wright }
613472b9844SJames Wright }
614472b9844SJames Wright
615472b9844SJames Wright PetscCall(DMPlexSymmetrize(*dm));
616472b9844SJames Wright PetscCall(DMPlexStratify(*dm));
61701432a30SJames Wright if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(*dm));
618472b9844SJames Wright
619472b9844SJames Wright /* Read coordinates */
620472b9844SJames Wright PetscCall(DMSetCoordinateDim(*dm, coordDim));
621472b9844SJames Wright PetscCall(DMGetCoordinateDM(*dm, &cdm));
622472b9844SJames Wright PetscCall(DMGetLocalSection(cdm, &coordSection));
623472b9844SJames Wright PetscCall(PetscSectionSetNumFields(coordSection, 1));
624472b9844SJames Wright PetscCall(PetscSectionSetFieldComponents(coordSection, 0, coordDim));
625472b9844SJames Wright PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
626472b9844SJames Wright for (v = numCells; v < numCells + numVertices; ++v) {
627472b9844SJames Wright PetscCall(PetscSectionSetDof(coordSection, v, dim));
628472b9844SJames Wright PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, coordDim));
629472b9844SJames Wright }
630472b9844SJames Wright PetscCall(PetscSectionSetUp(coordSection));
631472b9844SJames Wright
632472b9844SJames Wright PetscCall(DMCreateLocalVector(cdm, &coordinates));
633472b9844SJames Wright PetscCall(VecGetArray(coordinates, &coords));
634472b9844SJames Wright if (rank == 0) {
635472b9844SJames Wright PetscInt off = 0;
636472b9844SJames Wright float *x[3];
637472b9844SJames Wright int z, d;
638472b9844SJames Wright
639472b9844SJames Wright PetscCall(PetscMalloc3(numVertices, &x[0], numVertices, &x[1], numVertices, &x[2]));
640472b9844SJames Wright for (z = 1; z <= nzones; ++z) {
641472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype;
642472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */
643472b9844SJames Wright cgsize_t range_min[3] = {1, 1, 1};
644472b9844SJames Wright cgsize_t range_max[3] = {1, 1, 1};
645472b9844SJames Wright int ngrids, ncoords;
646472b9844SJames Wright
6474c155f28SJames Wright PetscCallCGNSRead(cg_zone_read(cgid, B, z, buffer, sizes), *dm, 0);
648472b9844SJames Wright range_max[0] = sizes[0];
6494c155f28SJames Wright PetscCallCGNSRead(cg_ngrids(cgid, B, z, &ngrids), *dm, 0);
650472b9844SJames Wright PetscCheck(ngrids <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single grid, not %d", ngrids);
6514c155f28SJames Wright PetscCallCGNSRead(cg_ncoords(cgid, B, z, &ncoords), *dm, 0);
652472b9844SJames Wright PetscCheck(ncoords == coordDim, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a coordinate array for each dimension, not %d", ncoords);
653472b9844SJames Wright for (d = 0; d < coordDim; ++d) {
6544c155f28SJames Wright PetscCallCGNSRead(cg_coord_info(cgid, B, z, 1 + d, &datatype, buffer), *dm, 0);
6554c155f28SJames Wright PetscCallCGNSReadData(cg_coord_read(cgid, B, z, buffer, CGNS_ENUMV(RealSingle), range_min, range_max, x[d]), *dm, 0);
656472b9844SJames Wright }
657472b9844SJames Wright if (coordDim >= 1) {
658472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 0] = x[0][v];
659472b9844SJames Wright }
660472b9844SJames Wright if (coordDim >= 2) {
661472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 1] = x[1][v];
662472b9844SJames Wright }
663472b9844SJames Wright if (coordDim >= 3) {
664472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 2] = x[2][v];
665472b9844SJames Wright }
666472b9844SJames Wright off += sizes[0];
667472b9844SJames Wright }
668472b9844SJames Wright PetscCall(PetscFree3(x[0], x[1], x[2]));
669472b9844SJames Wright }
670472b9844SJames Wright PetscCall(VecRestoreArray(coordinates, &coords));
671472b9844SJames Wright
672472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
673472b9844SJames Wright PetscCall(VecSetBlockSize(coordinates, coordDim));
674472b9844SJames Wright PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
675472b9844SJames Wright PetscCall(VecDestroy(&coordinates));
676472b9844SJames Wright
677472b9844SJames Wright /* Read boundary conditions */
678472b9844SJames Wright PetscCall(DMGetNumLabels(*dm, &labelIdRange[0]));
679472b9844SJames Wright if (rank == 0) {
680472b9844SJames Wright CGNS_ENUMT(BCType_t) bctype;
681472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype;
682472b9844SJames Wright CGNS_ENUMT(PointSetType_t) pointtype;
683472b9844SJames Wright cgsize_t *points;
684472b9844SJames Wright PetscReal *normals;
685472b9844SJames Wright int normal[3];
686472b9844SJames Wright char *bcname = buffer;
687472b9844SJames Wright cgsize_t npoints, nnormals;
688472b9844SJames Wright int z, nbc, bc, c, ndatasets;
689472b9844SJames Wright
690472b9844SJames Wright for (z = 1; z <= nzones; ++z) {
6914c155f28SJames Wright PetscCallCGNSRead(cg_nbocos(cgid, B, z, &nbc), *dm, 0);
692472b9844SJames Wright for (bc = 1; bc <= nbc; ++bc) {
6934c155f28SJames Wright PetscCallCGNSRead(cg_boco_info(cgid, B, z, bc, bcname, &bctype, &pointtype, &npoints, normal, &nnormals, &datatype, &ndatasets), *dm, 0);
694472b9844SJames Wright PetscCall(DMCreateLabel(*dm, bcname));
695472b9844SJames Wright PetscCall(DMGetLabel(*dm, bcname, &label));
696472b9844SJames Wright PetscCall(PetscMalloc2(npoints, &points, nnormals, &normals));
6974c155f28SJames Wright PetscCallCGNSReadData(cg_boco_read(cgid, B, z, bc, points, (void *)normals), *dm, 0);
698472b9844SJames Wright if (pointtype == CGNS_ENUMV(ElementRange)) {
699472b9844SJames Wright // Range of cells: assuming half-open interval
700472b9844SJames Wright for (c = points[0]; c < points[1]; ++c) PetscCall(DMLabelSetValue(label, c - cellStart[z - 1], 1));
701472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(ElementList)) {
702472b9844SJames Wright // List of cells
703472b9844SJames Wright for (c = 0; c < npoints; ++c) PetscCall(DMLabelSetValue(label, points[c] - cellStart[z - 1], 1));
704472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(PointRange)) {
705472b9844SJames Wright CGNS_ENUMT(GridLocation_t) gridloc;
706472b9844SJames Wright
707472b9844SJames Wright // List of points:
708472b9844SJames Wright PetscCallCGNS(cg_goto(cgid, 1, "Zone_t", z, "BC_t", bc, "end"));
7094c155f28SJames Wright PetscCallCGNSRead(cg_gridlocation_read(&gridloc), *dm, 0);
710472b9844SJames Wright // Range of points: assuming half-open interval
711472b9844SJames Wright for (c = points[0]; c < points[1]; ++c) {
712472b9844SJames Wright if (gridloc == CGNS_ENUMV(Vertex)) PetscCall(DMLabelSetValue(label, c - vertStart[z - 1], 1));
713472b9844SJames Wright else PetscCall(DMLabelSetValue(label, c - cellStart[z - 1], 1));
714472b9844SJames Wright }
715472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(PointList)) {
716472b9844SJames Wright CGNS_ENUMT(GridLocation_t) gridloc;
717472b9844SJames Wright
718472b9844SJames Wright // List of points:
719472b9844SJames Wright PetscCallCGNS(cg_goto(cgid, 1, "Zone_t", z, "BC_t", bc, "end"));
7204c155f28SJames Wright PetscCallCGNSRead(cg_gridlocation_read(&gridloc), *dm, 0);
721472b9844SJames Wright for (c = 0; c < npoints; ++c) {
722472b9844SJames Wright if (gridloc == CGNS_ENUMV(Vertex)) PetscCall(DMLabelSetValue(label, points[c] - vertStart[z - 1], 1));
723472b9844SJames Wright else PetscCall(DMLabelSetValue(label, points[c] - cellStart[z - 1], 1));
724472b9844SJames Wright }
725472b9844SJames Wright } else SETERRQ(comm, PETSC_ERR_SUP, "Unsupported point set type %d", (int)pointtype);
726472b9844SJames Wright PetscCall(PetscFree2(points, normals));
727472b9844SJames Wright }
728472b9844SJames Wright }
729472b9844SJames Wright PetscCall(PetscFree2(cellStart, vertStart));
730472b9844SJames Wright }
731472b9844SJames Wright PetscCall(DMGetNumLabels(*dm, &labelIdRange[1]));
732472b9844SJames Wright PetscCallMPI(MPI_Bcast(labelIdRange, 2, MPIU_INT, 0, comm));
733472b9844SJames Wright
734472b9844SJames Wright /* Create BC labels at all processes */
735472b9844SJames Wright for (labelId = labelIdRange[0]; labelId < labelIdRange[1]; ++labelId) {
736472b9844SJames Wright char *labelName = buffer;
737472b9844SJames Wright size_t len = sizeof(buffer);
738472b9844SJames Wright const char *locName;
739472b9844SJames Wright
740472b9844SJames Wright if (rank == 0) {
741472b9844SJames Wright PetscCall(DMGetLabelByNum(*dm, labelId, &label));
742472b9844SJames Wright PetscCall(PetscObjectGetName((PetscObject)label, &locName));
743472b9844SJames Wright PetscCall(PetscStrncpy(labelName, locName, len));
744472b9844SJames Wright }
745472b9844SJames Wright PetscCallMPI(MPI_Bcast(labelName, (PetscMPIInt)len, MPIU_INT, 0, comm));
746472b9844SJames Wright PetscCallMPI(DMCreateLabel(*dm, labelName));
747472b9844SJames Wright }
748472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
749472b9844SJames Wright }
750472b9844SJames Wright
751*3458b7b5SJames Wright typedef struct {
752*3458b7b5SJames Wright cgsize_t start, end;
753*3458b7b5SJames Wright } CGRange;
754*3458b7b5SJames Wright
755*3458b7b5SJames Wright // Creates a PetscLayout from the given sizes, but adjusts the ranges by the offset. So the first rank ranges will be [offset, offset + local_size) rather than [0, local_size)
PetscLayoutCreateFromSizesAndOffset(MPI_Comm comm,PetscInt n,PetscInt N,PetscInt bs,PetscInt offset,PetscLayout * map)756*3458b7b5SJames Wright static PetscErrorCode PetscLayoutCreateFromSizesAndOffset(MPI_Comm comm, PetscInt n, PetscInt N, PetscInt bs, PetscInt offset, PetscLayout *map)
757*3458b7b5SJames Wright {
758*3458b7b5SJames Wright PetscLayout init;
759*3458b7b5SJames Wright const PetscInt *ranges;
760*3458b7b5SJames Wright PetscInt *new_ranges;
761*3458b7b5SJames Wright PetscMPIInt num_ranks;
762*3458b7b5SJames Wright
763*3458b7b5SJames Wright PetscFunctionBegin;
764*3458b7b5SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, n, N, bs, &init));
765*3458b7b5SJames Wright PetscCall(PetscLayoutGetRanges(init, &ranges));
766*3458b7b5SJames Wright PetscCallMPI(MPI_Comm_size(comm, &num_ranks));
767*3458b7b5SJames Wright PetscCall(PetscMalloc1(num_ranks + 1, &new_ranges));
768*3458b7b5SJames Wright PetscCall(PetscArraycpy(new_ranges, ranges, num_ranks + 1));
769*3458b7b5SJames Wright for (PetscInt r = 0; r < num_ranks + 1; r++) new_ranges[r] += offset;
770*3458b7b5SJames Wright PetscCall(PetscLayoutCreateFromRanges(comm, new_ranges, PETSC_OWN_POINTER, bs, map));
771*3458b7b5SJames Wright PetscCall(PetscLayoutDestroy(&init));
772*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
773*3458b7b5SJames Wright }
774*3458b7b5SJames Wright
775*3458b7b5SJames Wright /**
776*3458b7b5SJames Wright @brief Creates connectivity array of CGNS elements' corners in Plex ordering, with a `PetscSection` to describe the data layout
777*3458b7b5SJames Wright
778*3458b7b5SJames Wright @param[in] dm `DM`
779*3458b7b5SJames Wright @param[in] cgid CGNS file ID
780*3458b7b5SJames Wright @param[in] base CGNS base ID
781*3458b7b5SJames Wright @param[in] zone CGNS zone ID
782*3458b7b5SJames Wright @param[in] num_sections Number of sections to put in connectivity
783*3458b7b5SJames Wright @param[in] section_ids CGNS section IDs to obtain connectivity from
784*3458b7b5SJames Wright @param[out] section Section describing the connectivity for each element
785*3458b7b5SJames Wright @param[out] cellTypes Array specifying the CGNS ElementType_t for each element
786*3458b7b5SJames Wright @param[out] cell_ids CGNS IDs of the cells
787*3458b7b5SJames Wright @param[out] layouts Array of `PetscLayout` that describes the distributed ownership of the cells in each `section_ids`
788*3458b7b5SJames Wright @param[out] connectivity Array of the cell connectivity, described by `section`. The vertices are the local Plex IDs
789*3458b7b5SJames Wright
790*3458b7b5SJames Wright @description
791*3458b7b5SJames Wright
792*3458b7b5SJames Wright Each point in `section` corresponds to the `cellTypes` and `cell_ids` arrays.
793*3458b7b5SJames Wright The dof and offset of `section` maps into the `connectivity` array.
794*3458b7b5SJames Wright
795*3458b7b5SJames Wright The `layouts` array is intended to be used with `PetscLayoutFindOwnerIndex_CGNSSectionLayouts()`
796*3458b7b5SJames Wright **/
DMPlexCGNS_CreateCornersConnectivitySection(DM dm,PetscInt cgid,int base,int zone,PetscInt num_sections,const int section_ids[],PetscSection * section,CGNS_ENUMT (ElementType_t)* cellTypes[],PetscInt * cell_ids[],PetscLayout * layouts[],PetscInt * connectivity[])797*3458b7b5SJames Wright static PetscErrorCode DMPlexCGNS_CreateCornersConnectivitySection(DM dm, PetscInt cgid, int base, int zone, PetscInt num_sections, const int section_ids[], PetscSection *section, CGNS_ENUMT(ElementType_t) * cellTypes[], PetscInt *cell_ids[], PetscLayout *layouts[], PetscInt *connectivity[])
798*3458b7b5SJames Wright {
799*3458b7b5SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
800*3458b7b5SJames Wright PetscSection section_;
801*3458b7b5SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1];
802*3458b7b5SJames Wright CGNS_ENUMT(ElementType_t) * sectionCellTypes, *cellTypes_;
803*3458b7b5SJames Wright CGRange *ranges;
804*3458b7b5SJames Wright PetscInt nlocal_cells = 0, global_cell_dim = -1;
805*3458b7b5SJames Wright PetscSegBuffer conn_sb;
806*3458b7b5SJames Wright PetscLayout *layouts_;
807*3458b7b5SJames Wright
808*3458b7b5SJames Wright PetscFunctionBegin;
809*3458b7b5SJames Wright PetscCall(PetscMalloc2(num_sections, &ranges, num_sections, §ionCellTypes));
810*3458b7b5SJames Wright PetscCall(PetscMalloc1(num_sections, &layouts_));
811*3458b7b5SJames Wright for (PetscInt s = 0; s < num_sections; s++) {
812*3458b7b5SJames Wright int nbndry, parentFlag;
813*3458b7b5SJames Wright PetscInt local_size;
814*3458b7b5SJames Wright
815*3458b7b5SJames Wright PetscCallCGNSRead(cg_section_read(cgid, base, zone, section_ids[s], buffer, §ionCellTypes[s], &ranges[s].start, &ranges[s].end, &nbndry, &parentFlag), dm, 0);
816*3458b7b5SJames Wright PetscCheck(sectionCellTypes[s] != CGNS_ENUMV(NGON_n) && sectionCellTypes[s] != CGNS_ENUMV(NFACE_n), comm, PETSC_ERR_SUP, "CGNS reader does not support elements of type NGON_n or NFACE_n");
817*3458b7b5SJames Wright PetscInt num_section_cells = ranges[s].end - ranges[s].start + 1;
818*3458b7b5SJames Wright PetscCall(PetscLayoutCreateFromSizesAndOffset(comm, PETSC_DECIDE, num_section_cells, 1, ranges[s].start, &layouts_[s]));
819*3458b7b5SJames Wright PetscCall(PetscLayoutGetLocalSize(layouts_[s], &local_size));
820*3458b7b5SJames Wright nlocal_cells += local_size;
821*3458b7b5SJames Wright }
822*3458b7b5SJames Wright PetscCall(PetscSectionCreate(comm, §ion_));
823*3458b7b5SJames Wright PetscCall(PetscSectionSetChart(section_, 0, nlocal_cells));
824*3458b7b5SJames Wright
825*3458b7b5SJames Wright PetscCall(PetscMalloc1(nlocal_cells, cell_ids));
826*3458b7b5SJames Wright PetscCall(PetscMalloc1(nlocal_cells, &cellTypes_));
827*3458b7b5SJames Wright PetscCall(PetscSegBufferCreate(sizeof(PetscInt), nlocal_cells * 2, &conn_sb));
828*3458b7b5SJames Wright for (PetscInt s = 0, c = 0; s < num_sections; s++) {
829*3458b7b5SJames Wright PetscInt mystart, myend, myowned;
830*3458b7b5SJames Wright
831*3458b7b5SJames Wright PetscCall(PetscLayoutGetRange(layouts_[s], &mystart, &myend));
832*3458b7b5SJames Wright PetscCall(PetscLayoutGetLocalSize(layouts_[s], &myowned));
833*3458b7b5SJames Wright if (sectionCellTypes[s] == CGNS_ENUMV(MIXED)) {
834*3458b7b5SJames Wright cgsize_t *offsets, *conn_cg;
835*3458b7b5SJames Wright
836*3458b7b5SJames Wright PetscCall(PetscMalloc1(myowned + 1, &offsets)); // The last element in the array is the total size of the connectivity for the given [start,end] range
837*3458b7b5SJames Wright PetscCallCGNSRead(cgp_poly_elements_read_data_offsets(cgid, base, zone, section_ids[s], mystart, myend - 1, offsets), dm, 0);
838*3458b7b5SJames Wright PetscCall(PetscMalloc1(offsets[myowned + 1], &conn_cg));
839*3458b7b5SJames Wright PetscCallCGNSRead(cgp_poly_elements_read_data_elements(cgid, base, zone, section_ids[s], mystart, myend - 1, offsets, conn_cg), dm, 0);
840*3458b7b5SJames Wright for (PetscInt i = 0; i < myowned; i++) {
841*3458b7b5SJames Wright DMPolytopeType dm_cell_type = DM_POLYTOPE_UNKNOWN;
842*3458b7b5SJames Wright PetscInt numCorners, cell_dim, *conn_sb_seg;
843*3458b7b5SJames Wright const int *perm;
844*3458b7b5SJames Wright
845*3458b7b5SJames Wright (*cell_ids)[c] = mystart + i;
846*3458b7b5SJames Wright
847*3458b7b5SJames Wright cellTypes_[c] = (CGNS_ENUMT(ElementType_t))conn_cg[offsets[i]];
848*3458b7b5SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellTypes_[c], &dm_cell_type, &numCorners, &cell_dim));
849*3458b7b5SJames Wright if (global_cell_dim == -1) global_cell_dim = cell_dim;
850*3458b7b5SJames Wright else
851*3458b7b5SJames Wright PetscCheck(cell_dim == global_cell_dim, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Can only combine cells of the same dimension. Global cell dimension detected as %" PetscInt_FMT ", but CGNS element %" PetscInt_FMT " is dimension %" PetscInt_FMT, global_cell_dim, (*cell_ids)[c], cell_dim);
852*3458b7b5SJames Wright PetscCall(PetscSegBufferGetInts(conn_sb, numCorners, &conn_sb_seg));
853*3458b7b5SJames Wright
854*3458b7b5SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numCorners, NULL, &perm));
855*3458b7b5SJames Wright for (PetscInt v = 0; v < numCorners; ++v) conn_sb_seg[perm[v]] = conn_cg[offsets[i] + 1 + v];
856*3458b7b5SJames Wright PetscCall(PetscSectionSetDof(section_, c, numCorners));
857*3458b7b5SJames Wright c++;
858*3458b7b5SJames Wright }
859*3458b7b5SJames Wright PetscCall(PetscFree(offsets));
860*3458b7b5SJames Wright PetscCall(PetscFree(conn_cg));
861*3458b7b5SJames Wright } else {
862*3458b7b5SJames Wright PetscInt numCorners, cell_dim;
863*3458b7b5SJames Wright PetscInt *conn_sb_seg;
864*3458b7b5SJames Wright DMPolytopeType dm_cell_type = DM_POLYTOPE_UNKNOWN;
865*3458b7b5SJames Wright int npe; // nodes per element
866*3458b7b5SJames Wright const int *perm;
867*3458b7b5SJames Wright cgsize_t *conn_cg;
868*3458b7b5SJames Wright
869*3458b7b5SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(sectionCellTypes[s], &dm_cell_type, &numCorners, &cell_dim));
870*3458b7b5SJames Wright if (global_cell_dim == -1) global_cell_dim = cell_dim;
871*3458b7b5SJames Wright else
872*3458b7b5SJames Wright PetscCheck(cell_dim == global_cell_dim, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Can only combine cells of the same dimension. Global cell dimension detected as %" PetscInt_FMT ", but CGNS element %" PetscInt_FMT " is dimension %" PetscInt_FMT, global_cell_dim, (*cell_ids)[c], cell_dim);
873*3458b7b5SJames Wright
874*3458b7b5SJames Wright PetscCallCGNSRead(cg_npe(sectionCellTypes[s], &npe), dm, 0);
875*3458b7b5SJames Wright PetscCall(PetscMalloc1(myowned * npe, &conn_cg));
876*3458b7b5SJames Wright PetscCallCGNSRead(cgp_elements_read_data(cgid, base, zone, section_ids[s], mystart, myend - 1, conn_cg), dm, 0);
877*3458b7b5SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numCorners, NULL, &perm));
878*3458b7b5SJames Wright PetscCall(PetscSegBufferGetInts(conn_sb, numCorners * myowned, &conn_sb_seg));
879*3458b7b5SJames Wright for (PetscInt i = 0; i < myowned; i++) {
880*3458b7b5SJames Wright (*cell_ids)[c] = mystart + i;
881*3458b7b5SJames Wright cellTypes_[c] = sectionCellTypes[s];
882*3458b7b5SJames Wright for (PetscInt v = 0; v < numCorners; ++v) conn_sb_seg[i * numCorners + perm[v]] = conn_cg[i * npe + v];
883*3458b7b5SJames Wright PetscCall(PetscSectionSetDof(section_, c, numCorners));
884*3458b7b5SJames Wright c++;
885*3458b7b5SJames Wright }
886*3458b7b5SJames Wright PetscCall(PetscFree(conn_cg));
887*3458b7b5SJames Wright }
888*3458b7b5SJames Wright }
889*3458b7b5SJames Wright
890*3458b7b5SJames Wright PetscCall(PetscSectionSetUp(section_));
891*3458b7b5SJames Wright *section = section_;
892*3458b7b5SJames Wright PetscCall(PetscSegBufferExtractAlloc(conn_sb, connectivity));
893*3458b7b5SJames Wright PetscInt connSize;
894*3458b7b5SJames Wright PetscCall(PetscSectionGetStorageSize(section_, &connSize));
895*3458b7b5SJames Wright for (PetscInt i = 0; i < connSize; i++) (*connectivity)[i] -= 1; // vertices should be 0-based indexing for consistency with DMPlexBuildFromCellListParallel()
896*3458b7b5SJames Wright *layouts = layouts_;
897*3458b7b5SJames Wright if (cellTypes) *cellTypes = cellTypes_;
898*3458b7b5SJames Wright else PetscCall(PetscFree(cellTypes_));
899*3458b7b5SJames Wright
900*3458b7b5SJames Wright PetscCall(PetscSegBufferDestroy(&conn_sb));
901*3458b7b5SJames Wright PetscCall(PetscFree2(ranges, sectionCellTypes));
902*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
903*3458b7b5SJames Wright }
904*3458b7b5SJames Wright
PetscFindIntUnsorted(PetscInt key,PetscInt size,const PetscInt array[],PetscInt * loc)905*3458b7b5SJames Wright static inline PetscErrorCode PetscFindIntUnsorted(PetscInt key, PetscInt size, const PetscInt array[], PetscInt *loc)
906*3458b7b5SJames Wright {
907*3458b7b5SJames Wright PetscFunctionBegin;
908*3458b7b5SJames Wright *loc = -1;
909*3458b7b5SJames Wright for (PetscInt i = 0; i < size; i++) {
910*3458b7b5SJames Wright if (array[i] == key) {
911*3458b7b5SJames Wright *loc = i;
912*3458b7b5SJames Wright break;
913*3458b7b5SJames Wright }
914*3458b7b5SJames Wright }
915*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
916*3458b7b5SJames Wright }
917*3458b7b5SJames Wright
918*3458b7b5SJames Wright // Same as `PetscLayoutFindOwnerIndex()`, but does not fail if owner not in PetscLayout
PetscLayoutFindOwnerIndex_Internal(PetscLayout map,PetscInt idx,PetscMPIInt * owner,PetscInt * lidx,PetscBool * found_owner)919*3458b7b5SJames Wright static PetscErrorCode PetscLayoutFindOwnerIndex_Internal(PetscLayout map, PetscInt idx, PetscMPIInt *owner, PetscInt *lidx, PetscBool *found_owner)
920*3458b7b5SJames Wright {
921*3458b7b5SJames Wright PetscMPIInt lo = 0, hi, t;
922*3458b7b5SJames Wright
923*3458b7b5SJames Wright PetscFunctionBegin;
924*3458b7b5SJames Wright PetscAssert((map->n >= 0) && (map->N >= 0) && (map->range), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscLayoutSetUp() must be called first");
925*3458b7b5SJames Wright if (owner) *owner = -1;
926*3458b7b5SJames Wright if (lidx) *lidx = -1;
927*3458b7b5SJames Wright if (idx < map->range[0] && idx >= map->range[map->size + 1]) {
928*3458b7b5SJames Wright *found_owner = PETSC_FALSE;
929*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
930*3458b7b5SJames Wright }
931*3458b7b5SJames Wright hi = map->size;
932*3458b7b5SJames Wright while (hi - lo > 1) {
933*3458b7b5SJames Wright t = lo + (hi - lo) / 2;
934*3458b7b5SJames Wright if (idx < map->range[t]) hi = t;
935*3458b7b5SJames Wright else lo = t;
936*3458b7b5SJames Wright }
937*3458b7b5SJames Wright if (owner) *owner = lo;
938*3458b7b5SJames Wright if (lidx) *lidx = idx - map->range[lo];
939*3458b7b5SJames Wright if (found_owner) *found_owner = PETSC_TRUE;
940*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
941*3458b7b5SJames Wright }
942*3458b7b5SJames Wright
943*3458b7b5SJames Wright // This function assumes that there is an array that `maps` describes the layout too. Locally, the range of each map is concatenated onto each other.
944*3458b7b5SJames Wright // So [maps[0].start, ..., maps[0].end - 1, maps[1].start, ..., maps[1].end - 1, ...]
945*3458b7b5SJames Wright // The returned index is the index into this array
PetscLayoutFindOwnerIndex_CGNSSectionLayouts(PetscLayout maps[],PetscInt nmaps,PetscInt idx,PetscMPIInt * owner,PetscInt * lidx,PetscInt * mapidx)946*3458b7b5SJames Wright static PetscErrorCode PetscLayoutFindOwnerIndex_CGNSSectionLayouts(PetscLayout maps[], PetscInt nmaps, PetscInt idx, PetscMPIInt *owner, PetscInt *lidx, PetscInt *mapidx)
947*3458b7b5SJames Wright {
948*3458b7b5SJames Wright PetscFunctionBegin;
949*3458b7b5SJames Wright for (PetscInt m = 0; m < nmaps; m++) {
950*3458b7b5SJames Wright PetscBool found_owner = PETSC_FALSE;
951*3458b7b5SJames Wright PetscCall(PetscLayoutFindOwnerIndex_Internal(maps[m], idx, owner, lidx, &found_owner));
952*3458b7b5SJames Wright if (found_owner) {
953*3458b7b5SJames Wright // Now loop back through the previous maps to get the local offset for the containing index
954*3458b7b5SJames Wright for (PetscInt mm = m - 1; mm >= 0; mm--) {
955*3458b7b5SJames Wright PetscInt size = maps[mm]->range[*owner + 1] - maps[mm]->range[*owner];
956*3458b7b5SJames Wright *lidx += size;
957*3458b7b5SJames Wright }
958*3458b7b5SJames Wright if (mapidx) *mapidx = m;
959*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
960*3458b7b5SJames Wright }
961*3458b7b5SJames Wright }
962*3458b7b5SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "CGNS id %" PetscInt_FMT " not found in layouts", idx);
963*3458b7b5SJames Wright }
964*3458b7b5SJames Wright
965*3458b7b5SJames Wright /*
966*3458b7b5SJames Wright @brief Matching root and leaf indices across processes, allowing multiple roots per leaf
967*3458b7b5SJames Wright
968*3458b7b5SJames Wright Collective
969*3458b7b5SJames Wright
970*3458b7b5SJames Wright Input Parameters:
971*3458b7b5SJames Wright + layout - `PetscLayout` defining the global index space and the MPI rank that brokers each index
972*3458b7b5SJames Wright . numRootIndices - size of `rootIndices`
973*3458b7b5SJames Wright . rootIndices - array of global indices of which this process requests ownership
974*3458b7b5SJames Wright . rootLocalIndices - root local index permutation (`NULL` if no permutation)
975*3458b7b5SJames Wright . rootLocalOffset - offset to be added to `rootLocalIndices`
976*3458b7b5SJames Wright . numLeafIndices - size of `leafIndices`
977*3458b7b5SJames Wright . leafIndices - array of global indices with which this process requires data associated
978*3458b7b5SJames Wright . leafLocalIndices - leaf local index permutation (`NULL` if no permutation)
979*3458b7b5SJames Wright - leafLocalOffset - offset to be added to `leafLocalIndices`
980*3458b7b5SJames Wright
981*3458b7b5SJames Wright Output Parameters:
982*3458b7b5SJames Wright + matchSection - The `PetscSection` describing the layout of `matches` with respect to the `leafIndices` (the points of the section indexes into `leafIndices`)
983*3458b7b5SJames Wright - matches - Array of `PetscSFNode` denoting the location (rank and index) of the root matching the leaf.
984*3458b7b5SJames Wright
985*3458b7b5SJames Wright Example 1:
986*3458b7b5SJames Wright .vb
987*3458b7b5SJames Wright rank : 0 1 2
988*3458b7b5SJames Wright rootIndices : [1 0 2] [3] [3]
989*3458b7b5SJames Wright rootLocalOffset : 100 200 300
990*3458b7b5SJames Wright layout : [0 1] [2] [3]
991*3458b7b5SJames Wright leafIndices : [0] [2] [0 3]
992*3458b7b5SJames Wright leafLocalOffset : 400 500 600
993*3458b7b5SJames Wright
994*3458b7b5SJames Wright would build the following result
995*3458b7b5SJames Wright
996*3458b7b5SJames Wright rank 0: [0] 400 <- [0] (0,101)
997*3458b7b5SJames Wright ------------------------------
998*3458b7b5SJames Wright rank 1: [0] 500 <- [0] (0,102)
999*3458b7b5SJames Wright ------------------------------
1000*3458b7b5SJames Wright rank 2: [0] 600 <- [0] (0,101)
1001*3458b7b5SJames Wright [1] 601 <- [1] (1,200)
1002*3458b7b5SJames Wright [1] 601 <- [2] (2,300)
1003*3458b7b5SJames Wright | | | |
1004*3458b7b5SJames Wright | | | + `matches`, the rank and index of the respective match with the leaf index
1005*3458b7b5SJames Wright | | + index into `matches` array
1006*3458b7b5SJames Wright | + the leaves for the respective root
1007*3458b7b5SJames Wright + The point in `matchSection` (indexes into `leafIndices`)
1008*3458b7b5SJames Wright
1009*3458b7b5SJames Wright For rank 2, the `matchSection` would be:
1010*3458b7b5SJames Wright
1011*3458b7b5SJames Wright [0]: (1, 0)
1012*3458b7b5SJames Wright [1]: (2, 1)
1013*3458b7b5SJames Wright | | |
1014*3458b7b5SJames Wright | | + offset
1015*3458b7b5SJames Wright | + ndof
1016*3458b7b5SJames Wright + point
1017*3458b7b5SJames Wright .ve
1018*3458b7b5SJames Wright
1019*3458b7b5SJames Wright Notes:
1020*3458b7b5SJames Wright This function is identical to `PetscSFCreateByMatchingIndices()` except it includes *all* matching indices instead of designating a single rank as the "owner".
1021*3458b7b5SJames Wright Attempting to create an SF with all matching indices would create an invalid SF, thus we give an array of `matches` and `matchSection` to describe the layout
1022*3458b7b5SJames Wright Compare the examples in this document to those in `PetscSFCreateByMatchingIndices()`.
1023*3458b7b5SJames Wright
1024*3458b7b5SJames Wright .seealso: [](sec_petscsf), `PetscSF`, `PetscSFCreate()`, `PetscSFCreateByMatchingIndices()`
1025*3458b7b5SJames Wright */
PetscSFFindMatchingIndices(PetscLayout layout,PetscInt numRootIndices,const PetscInt rootIndices[],const PetscInt rootLocalIndices[],PetscInt rootLocalOffset,PetscInt numLeafIndices,const PetscInt leafIndices[],const PetscInt leafLocalIndices[],PetscInt leafLocalOffset,PetscSection * matchSection,PetscSFNode * matches[])1026*3458b7b5SJames Wright static PetscErrorCode PetscSFFindMatchingIndices(PetscLayout layout, PetscInt numRootIndices, const PetscInt rootIndices[], const PetscInt rootLocalIndices[], PetscInt rootLocalOffset, PetscInt numLeafIndices, const PetscInt leafIndices[], const PetscInt leafLocalIndices[], PetscInt leafLocalOffset, PetscSection *matchSection, PetscSFNode *matches[])
1027*3458b7b5SJames Wright {
1028*3458b7b5SJames Wright MPI_Comm comm = layout->comm;
1029*3458b7b5SJames Wright PetscMPIInt rank;
1030*3458b7b5SJames Wright PetscSF sf1;
1031*3458b7b5SJames Wright PetscSection sectionBuffer, matchSection_;
1032*3458b7b5SJames Wright PetscInt numMatches;
1033*3458b7b5SJames Wright PetscSFNode *roots, *buffer, *matches_;
1034*3458b7b5SJames Wright PetscInt N, n, pStart, pEnd;
1035*3458b7b5SJames Wright PetscBool areIndicesSame;
1036*3458b7b5SJames Wright
1037*3458b7b5SJames Wright PetscFunctionBegin;
1038*3458b7b5SJames Wright if (rootIndices) PetscAssertPointer(rootIndices, 3);
1039*3458b7b5SJames Wright if (rootLocalIndices) PetscAssertPointer(rootLocalIndices, 4);
1040*3458b7b5SJames Wright if (leafIndices) PetscAssertPointer(leafIndices, 7);
1041*3458b7b5SJames Wright if (leafLocalIndices) PetscAssertPointer(leafLocalIndices, 8);
1042*3458b7b5SJames Wright PetscCheck(numRootIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
1043*3458b7b5SJames Wright PetscCheck(numLeafIndices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
1044*3458b7b5SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank));
1045*3458b7b5SJames Wright PetscCall(PetscLayoutSetUp(layout));
1046*3458b7b5SJames Wright PetscCall(PetscLayoutGetSize(layout, &N));
1047*3458b7b5SJames Wright PetscCall(PetscLayoutGetLocalSize(layout, &n));
1048*3458b7b5SJames Wright areIndicesSame = (PetscBool)(leafIndices == rootIndices);
1049*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &areIndicesSame, 1, MPI_C_BOOL, MPI_LAND, comm));
1050*3458b7b5SJames Wright PetscCheck(!areIndicesSame || numLeafIndices == numRootIndices, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
1051*3458b7b5SJames Wright if (PetscDefined(USE_DEBUG)) {
1052*3458b7b5SJames Wright PetscInt N1 = PETSC_INT_MIN;
1053*3458b7b5SJames Wright for (PetscInt i = 0; i < numRootIndices; i++)
1054*3458b7b5SJames Wright if (rootIndices[i] > N1) N1 = rootIndices[i];
1055*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
1056*3458b7b5SJames Wright PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
1057*3458b7b5SJames Wright if (!areIndicesSame) {
1058*3458b7b5SJames Wright N1 = PETSC_INT_MIN;
1059*3458b7b5SJames Wright for (PetscInt i = 0; i < numLeafIndices; i++)
1060*3458b7b5SJames Wright if (leafIndices[i] > N1) N1 = leafIndices[i];
1061*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
1062*3458b7b5SJames Wright PetscCheck(N1 < N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. leaf index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
1063*3458b7b5SJames Wright }
1064*3458b7b5SJames Wright }
1065*3458b7b5SJames Wright
1066*3458b7b5SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank));
1067*3458b7b5SJames Wright { /* Reduce: roots -> buffer */
1068*3458b7b5SJames Wright // Data in buffer described by section_buffer. The chart of `section_buffer` maps onto the local portion of `layout`, with dofs denoting how many matches there are.
1069*3458b7b5SJames Wright PetscInt bufsize;
1070*3458b7b5SJames Wright const PetscInt *root_degree;
1071*3458b7b5SJames Wright
1072*3458b7b5SJames Wright PetscCall(PetscSFCreate(comm, &sf1));
1073*3458b7b5SJames Wright PetscCall(PetscSFSetFromOptions(sf1));
1074*3458b7b5SJames Wright PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
1075*3458b7b5SJames Wright
1076*3458b7b5SJames Wright PetscCall(PetscSFComputeDegreeBegin(sf1, &root_degree));
1077*3458b7b5SJames Wright PetscCall(PetscSFComputeDegreeEnd(sf1, &root_degree));
1078*3458b7b5SJames Wright PetscCall(PetscSectionCreate(comm, §ionBuffer));
1079*3458b7b5SJames Wright PetscCall(PetscSectionSetChart(sectionBuffer, 0, n));
1080*3458b7b5SJames Wright PetscCall(PetscMalloc1(numRootIndices, &roots));
1081*3458b7b5SJames Wright for (PetscInt i = 0; i < numRootIndices; ++i) {
1082*3458b7b5SJames Wright roots[i].rank = rank;
1083*3458b7b5SJames Wright roots[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
1084*3458b7b5SJames Wright }
1085*3458b7b5SJames Wright for (PetscInt i = 0; i < n; i++) PetscCall(PetscSectionSetDof(sectionBuffer, i, root_degree[i]));
1086*3458b7b5SJames Wright PetscCall(PetscSectionSetUp(sectionBuffer));
1087*3458b7b5SJames Wright PetscCall(PetscSectionGetStorageSize(sectionBuffer, &bufsize));
1088*3458b7b5SJames Wright PetscCall(PetscMalloc1(bufsize, &buffer));
1089*3458b7b5SJames Wright for (PetscInt i = 0; i < bufsize; ++i) {
1090*3458b7b5SJames Wright buffer[i].index = -1;
1091*3458b7b5SJames Wright buffer[i].rank = -1;
1092*3458b7b5SJames Wright }
1093*3458b7b5SJames Wright PetscCall(PetscSFGatherBegin(sf1, MPIU_SF_NODE, roots, buffer));
1094*3458b7b5SJames Wright PetscCall(PetscSFGatherEnd(sf1, MPIU_SF_NODE, roots, buffer));
1095*3458b7b5SJames Wright PetscCall(PetscFree(roots));
1096*3458b7b5SJames Wright }
1097*3458b7b5SJames Wright
1098*3458b7b5SJames Wright // Distribute data in buffers to the leaf locations. The chart of `sectionMatches` maps to `leafIndices`, with dofs denoting how many matches there are for each leaf.
1099*3458b7b5SJames Wright if (!areIndicesSame) PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
1100*3458b7b5SJames Wright PetscCall(PetscSectionCreate(comm, &matchSection_));
1101*3458b7b5SJames Wright PetscCall(PetscSectionMigrateData(sf1, MPIU_SF_NODE, sectionBuffer, buffer, matchSection_, (void **)&matches_, NULL));
1102*3458b7b5SJames Wright PetscCall(PetscSectionGetChart(matchSection_, &pStart, &pEnd));
1103*3458b7b5SJames Wright PetscCheck(pEnd - pStart == numLeafIndices, comm, PETSC_ERR_PLIB, "Section of matches has different chart size (%" PetscInt_FMT ") than number of leaf indices %" PetscInt_FMT ". Section chart is [%" PetscInt_FMT ", %" PetscInt_FMT ")", pEnd - pStart, numLeafIndices, pStart, pEnd);
1104*3458b7b5SJames Wright PetscCall(PetscSectionGetStorageSize(matchSection_, &numMatches));
1105*3458b7b5SJames Wright for (PetscInt p = pStart; p < pEnd; p++) {
1106*3458b7b5SJames Wright PetscInt ndofs;
1107*3458b7b5SJames Wright PetscCall(PetscSectionGetDof(matchSection_, p, &ndofs));
1108*3458b7b5SJames Wright PetscCheck(ndofs > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No match found for index %" PetscInt_FMT, leafIndices[p]);
1109*3458b7b5SJames Wright }
1110*3458b7b5SJames Wright
1111*3458b7b5SJames Wright *matchSection = matchSection_;
1112*3458b7b5SJames Wright *matches = matches_;
1113*3458b7b5SJames Wright
1114*3458b7b5SJames Wright PetscCall(PetscFree(buffer));
1115*3458b7b5SJames Wright PetscCall(PetscSectionDestroy(§ionBuffer));
1116*3458b7b5SJames Wright PetscCall(PetscSFDestroy(&sf1));
1117*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
1118*3458b7b5SJames Wright }
1119*3458b7b5SJames Wright
1120*3458b7b5SJames Wright /**
1121*3458b7b5SJames Wright @brief Match CGNS faces to their Plex equivalents
1122*3458b7b5SJames Wright
1123*3458b7b5SJames Wright @param[in] dm DM that holds the Plex to match against
1124*3458b7b5SJames Wright @param[in] nuniq_verts Number of unique CGNS vertices on this rank
1125*3458b7b5SJames Wright @param[in] uniq_verts Unique CGNS vertices on this rank
1126*3458b7b5SJames Wright @param[in] plex_vertex_offset Index offset to match `uniq_vertices` to their respective Plex vertices
1127*3458b7b5SJames Wright @param[in] NVertices Number of vertices for Layout for `PetscSFFindMatchingIndices()`
1128*3458b7b5SJames Wright @param[in] connSection PetscSection describing the CGNS face connectivity
1129*3458b7b5SJames Wright @param[in] face_ids Array of the CGNS face IDs
1130*3458b7b5SJames Wright @param[in] conn Array of the CGNS face connectivity
1131*3458b7b5SJames Wright @param[out] cg2plexSF PetscSF describing the mapping from owned CGNS faces to remote `plexFaces`
1132*3458b7b5SJames Wright @param[out] plexFaces Matching Plex face IDs
1133*3458b7b5SJames Wright
1134*3458b7b5SJames Wright @description
1135*3458b7b5SJames Wright
1136*3458b7b5SJames Wright `cg2plexSF` is a mapping from the owned CGNS faces to the rank whose local Plex has that face.
1137*3458b7b5SJames Wright `plexFaces` holds the actual mesh point in the local Plex that corresponds to the owned CGNS face (which is the root)
1138*3458b7b5SJames Wright
1139*3458b7b5SJames Wright cg2plexSF
1140*3458b7b5SJames Wright __________|__________
1141*3458b7b5SJames Wright | |
1142*3458b7b5SJames Wright
1143*3458b7b5SJames Wright [F0_11] -----> [P0_0] [38]
1144*3458b7b5SJames Wright [F0_12] -- Rank 0
1145*3458b7b5SJames Wright ~~~~~~~~~ \ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1146*3458b7b5SJames Wright --> [P1_0] [59] Rank 1
1147*3458b7b5SJames Wright [F1_13] -----> [P1_1] [98]
1148*3458b7b5SJames Wright | | |
1149*3458b7b5SJames Wright | | + plexFaces, maps the leaves of cg2plexSF to local Plex face mesh points
1150*3458b7b5SJames Wright | + Leaves of cg2plexSF. P(rank)_(root_index)
1151*3458b7b5SJames Wright + Roots of cg2plexSF, F(rank)_(CGNS face ID)
1152*3458b7b5SJames Wright
1153*3458b7b5SJames Wright Note that, unlike a pointSF, the leaves of `cg2plexSF` do not map onto chart of the local Plex, but just onto an array.
1154*3458b7b5SJames Wright The plexFaces array is then what maps the leaves to the actual local Plex mesh points.
1155*3458b7b5SJames Wright
1156*3458b7b5SJames Wright `plex_vertex_offset` is used to map the CGNS vertices in `uniq_vertices` to their respective Plex vertices.
1157*3458b7b5SJames Wright From `DMPlexBuildFromCellListParallel()`, the mapping of CGNS vertices to Plex vertices is uniq_vert[i] -> i + plex_vertex_offset, where the right side is the Plex point ID.
1158*3458b7b5SJames Wright So with `plex_vertex_offset = 5`,
1159*3458b7b5SJames Wright uniq_vertices: [19, 52, 1, 89]
1160*3458b7b5SJames Wright plex_point_ids: [5, 6, 7, 8]
1161*3458b7b5SJames Wright **/
DMPlexCGNS_MatchCGNSFacesToPlexFaces(DM dm,PetscInt nuniq_verts,const PetscInt uniq_verts[],PetscInt plex_vertex_offset,PetscInt NVertices,PetscSection connSection,const PetscInt face_ids[],const PetscInt conn[],PetscSF * cg2plexSF,PetscInt * plexFaces[])1162*3458b7b5SJames Wright static PetscErrorCode DMPlexCGNS_MatchCGNSFacesToPlexFaces(DM dm, PetscInt nuniq_verts, const PetscInt uniq_verts[], PetscInt plex_vertex_offset, PetscInt NVertices, PetscSection connSection, const PetscInt face_ids[], const PetscInt conn[], PetscSF *cg2plexSF, PetscInt *plexFaces[])
1163*3458b7b5SJames Wright {
1164*3458b7b5SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
1165*3458b7b5SJames Wright PetscMPIInt myrank, nranks;
1166*3458b7b5SJames Wright PetscInt fownedStart, fownedEnd, fownedSize;
1167*3458b7b5SJames Wright
1168*3458b7b5SJames Wright PetscFunctionBegin;
1169*3458b7b5SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &myrank));
1170*3458b7b5SJames Wright PetscCallMPI(MPI_Comm_size(comm, &nranks));
1171*3458b7b5SJames Wright
1172*3458b7b5SJames Wright { // -- Create cg2plexSF
1173*3458b7b5SJames Wright PetscInt nuniq_face_verts, *uniq_face_verts;
1174*3458b7b5SJames Wright PetscSection fvert2mvertSection;
1175*3458b7b5SJames Wright PetscSFNode *fvert2mvert = NULL;
1176*3458b7b5SJames Wright
1177*3458b7b5SJames Wright { // -- Create fvert2mvert, which map CGNS vertices in the owned-face connectivity to the CGNS vertices in the global mesh
1178*3458b7b5SJames Wright PetscLayout layout;
1179*3458b7b5SJames Wright
1180*3458b7b5SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NVertices, 1, &layout));
1181*3458b7b5SJames Wright { // Count locally unique vertices in the face connectivity
1182*3458b7b5SJames Wright PetscHSetI vhash;
1183*3458b7b5SJames Wright PetscInt off = 0, conn_size;
1184*3458b7b5SJames Wright
1185*3458b7b5SJames Wright PetscCall(PetscHSetICreate(&vhash));
1186*3458b7b5SJames Wright PetscCall(PetscSectionGetStorageSize(connSection, &conn_size));
1187*3458b7b5SJames Wright for (PetscInt v = 0; v < conn_size; ++v) PetscCall(PetscHSetIAdd(vhash, conn[v]));
1188*3458b7b5SJames Wright PetscCall(PetscHSetIGetSize(vhash, &nuniq_face_verts));
1189*3458b7b5SJames Wright PetscCall(PetscMalloc1(nuniq_face_verts, &uniq_face_verts));
1190*3458b7b5SJames Wright PetscCall(PetscHSetIGetElems(vhash, &off, uniq_face_verts));
1191*3458b7b5SJames Wright PetscCall(PetscHSetIDestroy(&vhash));
1192*3458b7b5SJames Wright PetscCheck(off == nuniq_face_verts, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, nuniq_face_verts);
1193*3458b7b5SJames Wright }
1194*3458b7b5SJames Wright PetscCall(PetscSortInt(nuniq_face_verts, uniq_face_verts));
1195*3458b7b5SJames Wright PetscCall(PetscSFFindMatchingIndices(layout, nuniq_verts, uniq_verts, NULL, 0, nuniq_face_verts, uniq_face_verts, NULL, 0, &fvert2mvertSection, &fvert2mvert));
1196*3458b7b5SJames Wright
1197*3458b7b5SJames Wright PetscCall(PetscLayoutDestroy(&layout));
1198*3458b7b5SJames Wright }
1199*3458b7b5SJames Wright
1200*3458b7b5SJames Wright PetscSFNode *plexFaceRemotes, *ownedFaceRemotes;
1201*3458b7b5SJames Wright PetscCount nPlexFaceRemotes;
1202*3458b7b5SJames Wright PetscInt *local_rank_count;
1203*3458b7b5SJames Wright
1204*3458b7b5SJames Wright PetscCall(PetscSectionGetChart(connSection, &fownedStart, &fownedEnd));
1205*3458b7b5SJames Wright fownedSize = fownedEnd - fownedStart;
1206*3458b7b5SJames Wright PetscCall(PetscCalloc1(nranks, &local_rank_count));
1207*3458b7b5SJames Wright
1208*3458b7b5SJames Wright { // Find the rank(s) whose local Plex has the owned CGNS face
1209*3458b7b5SJames Wright // We determine ownership by determining which ranks contain all the vertices in a face's connectivity
1210*3458b7b5SJames Wright PetscInt maxRanksPerVert;
1211*3458b7b5SJames Wright PetscInt *face_ranks;
1212*3458b7b5SJames Wright PetscSegBuffer plexFaceRemotes_SB, ownedFaceRemotes_SB;
1213*3458b7b5SJames Wright
1214*3458b7b5SJames Wright PetscCall(PetscSegBufferCreate(sizeof(PetscSFNode), fownedSize, &plexFaceRemotes_SB));
1215*3458b7b5SJames Wright PetscCall(PetscSegBufferCreate(sizeof(PetscSFNode), fownedSize, &ownedFaceRemotes_SB));
1216*3458b7b5SJames Wright PetscCall(PetscSectionGetMaxDof(fvert2mvertSection, &maxRanksPerVert));
1217*3458b7b5SJames Wright PetscCall(PetscMalloc1(maxRanksPerVert, &face_ranks));
1218*3458b7b5SJames Wright for (PetscInt f = fownedStart, f_i = 0; f < fownedEnd; f++, f_i++) {
1219*3458b7b5SJames Wright PetscInt fndof, foffset, lndof, loffset, idx, nface_ranks = 0;
1220*3458b7b5SJames Wright
1221*3458b7b5SJames Wright PetscCall(PetscSectionGetDof(connSection, f, &fndof));
1222*3458b7b5SJames Wright PetscCall(PetscSectionGetOffset(connSection, f, &foffset));
1223*3458b7b5SJames Wright PetscCall(PetscFindInt(conn[foffset + 0], nuniq_face_verts, uniq_face_verts, &idx));
1224*3458b7b5SJames Wright PetscCall(PetscSectionGetDof(fvert2mvertSection, idx, &lndof));
1225*3458b7b5SJames Wright PetscCall(PetscSectionGetOffset(fvert2mvertSection, idx, &loffset));
1226*3458b7b5SJames Wright // Loop over ranks of the first vertex in the face connectivity
1227*3458b7b5SJames Wright for (PetscInt l = 0; l < lndof; l++) {
1228*3458b7b5SJames Wright PetscInt rank = fvert2mvert[loffset + l].rank;
1229*3458b7b5SJames Wright // Loop over vertices of face (except for the first) to see if those vertices have the same candidate rank
1230*3458b7b5SJames Wright for (PetscInt v = 1; v < fndof; v++) {
1231*3458b7b5SJames Wright PetscInt ldndof, ldoffset, idx;
1232*3458b7b5SJames Wright PetscBool vert_has_rank = PETSC_FALSE;
1233*3458b7b5SJames Wright
1234*3458b7b5SJames Wright PetscCall(PetscFindInt(conn[foffset + v], nuniq_face_verts, uniq_face_verts, &idx));
1235*3458b7b5SJames Wright PetscCall(PetscSectionGetDof(fvert2mvertSection, idx, &ldndof));
1236*3458b7b5SJames Wright PetscCall(PetscSectionGetOffset(fvert2mvertSection, idx, &ldoffset));
1237*3458b7b5SJames Wright // Loop over ranks of the vth vertex to see if it has the candidate rank
1238*3458b7b5SJames Wright for (PetscInt ld = 0; ld < ldndof; ld++) vert_has_rank = (fvert2mvert[ldoffset + ld].rank == rank) || vert_has_rank;
1239*3458b7b5SJames Wright if (vert_has_rank) continue; // This vertex has the candidate rank, proceed to the next vertex
1240*3458b7b5SJames Wright else goto next_candidate_rank;
1241*3458b7b5SJames Wright }
1242*3458b7b5SJames Wright face_ranks[nface_ranks++] = rank;
1243*3458b7b5SJames Wright next_candidate_rank:
1244*3458b7b5SJames Wright continue;
1245*3458b7b5SJames Wright }
1246*3458b7b5SJames Wright PetscCheck(nface_ranks > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Rank containing CGNS face %" PetscInt_FMT " could not be found", face_ids[f_i]);
1247*3458b7b5SJames Wright
1248*3458b7b5SJames Wright // Once we have found the rank(s) whose Plex has the vertices of CGNS face `f`, we can begin to build the information for the SF.
1249*3458b7b5SJames Wright // We want the roots to be the CGNS faces and the leaves to be the corresponding Plex faces, but we have the opposite; for the owned face on myrank, we know the rank that has the corresponding Plex face.
1250*3458b7b5SJames Wright // To get the inverse, we assign each SF edge with a tuple of PetscSFNodes; one in `plexFaceRemotes` and the other in `ownedFaceRemotes`.
1251*3458b7b5SJames Wright // `plexFaceRemotes` has the rank and index of the Plex face.
1252*3458b7b5SJames Wright // `ownedFaceRemotes` has the rank and index of the owned CGNS face.
1253*3458b7b5SJames Wright // Note that `ownedFaceRemotes` is all on my rank (e.g. rank == myrank).
1254*3458b7b5SJames Wright //
1255*3458b7b5SJames Wright // Then, to build the `cg2plexSF`, we communicate the `ownedFaceRemotes` to the `plexFaceRemotes` (via SFReduce).
1256*3458b7b5SJames Wright // Those `ownedFaceRemotes` then act as the leaves to the roots on this process.
1257*3458b7b5SJames Wright //
1258*3458b7b5SJames Wright // Conceptually, this is the same as calling `PetscSFCreateInverseSF` on an SF with `iremotes = plexFaceRemotes` and the `ilocal = ownedFaceRemotes[:].index`.
1259*3458b7b5SJames Wright // However, we cannot use this much simpler way because when there are multiple matching Plex faces, `PetscSFCreateInverseSF()` will be invalid due to `ownedFaceRemotes[:].index` having repeated values (only root vertices of the SF graph may have degree > 1)
1260*3458b7b5SJames Wright PetscSFNode *plexFaceRemotes_buffer, *ownedFaceRemotes_buffer;
1261*3458b7b5SJames Wright PetscCall(PetscSegBufferGet(plexFaceRemotes_SB, nface_ranks, &plexFaceRemotes_buffer));
1262*3458b7b5SJames Wright PetscCall(PetscSegBufferGet(ownedFaceRemotes_SB, nface_ranks, &ownedFaceRemotes_buffer));
1263*3458b7b5SJames Wright for (PetscInt n = 0; n < nface_ranks; n++) {
1264*3458b7b5SJames Wright plexFaceRemotes_buffer[n].rank = face_ranks[n];
1265*3458b7b5SJames Wright local_rank_count[face_ranks[n]]++;
1266*3458b7b5SJames Wright ownedFaceRemotes_buffer[n] = (PetscSFNode){.rank = myrank, .index = f_i};
1267*3458b7b5SJames Wright }
1268*3458b7b5SJames Wright }
1269*3458b7b5SJames Wright PetscCall(PetscFree(face_ranks));
1270*3458b7b5SJames Wright
1271*3458b7b5SJames Wright PetscCall(PetscSegBufferGetSize(plexFaceRemotes_SB, &nPlexFaceRemotes));
1272*3458b7b5SJames Wright PetscCall(PetscSegBufferExtractAlloc(plexFaceRemotes_SB, &plexFaceRemotes));
1273*3458b7b5SJames Wright PetscCall(PetscSegBufferDestroy(&plexFaceRemotes_SB));
1274*3458b7b5SJames Wright PetscCall(PetscSegBufferExtractAlloc(ownedFaceRemotes_SB, &ownedFaceRemotes));
1275*3458b7b5SJames Wright PetscCall(PetscSegBufferDestroy(&ownedFaceRemotes_SB));
1276*3458b7b5SJames Wright
1277*3458b7b5SJames Wright // To get the index for plexFaceRemotes, we partition the leaves on each rank (e.g. the array that will hold the local Plex face mesh points) by each rank that has the CGNS owned rank.
1278*3458b7b5SJames Wright // For r in [0,numranks), local_rank_count[r] holds the number plexFaces that myrank holds.
1279*3458b7b5SJames Wright // This determines how large a partition the leaves on rank r need to create for myrank.
1280*3458b7b5SJames Wright // To get the offset into the leaves, we use Exscan to get rank_start.
1281*3458b7b5SJames Wright // For r in [0, numranks), rank_start[r] holds the offset into rank r's leaves that myrank will index into.
1282*3458b7b5SJames Wright
1283*3458b7b5SJames Wright // Below is an example:
1284*3458b7b5SJames Wright //
1285*3458b7b5SJames Wright // myrank: | 0 1 2
1286*3458b7b5SJames Wright // local_rank_count: | [3, 2, 0] [1, 0, 2] [2, 2, 1]
1287*3458b7b5SJames Wright // myrank_total_count: | 6 4 3
1288*3458b7b5SJames Wright // rank_start: | [0, 0, 0] [3, 2, 0] [4, 2, 2]
1289*3458b7b5SJames Wright // |
1290*3458b7b5SJames Wright // plexFaceRemotes: 0 | (0, 0) (2, 0) (2, 2) <-- (rank, index) tuples (e.g. PetscSFNode)
1291*3458b7b5SJames Wright // 1 | (1, 0) (2, 1) (0, 4)
1292*3458b7b5SJames Wright // 2 | (0, 1) (0, 3) (1, 2)
1293*3458b7b5SJames Wright // 3 | (0, 2) (0, 5)
1294*3458b7b5SJames Wright // 4 | (1, 1) (1, 3)
1295*3458b7b5SJames Wright //
1296*3458b7b5SJames Wright // leaves: 0 | (0, 0) (0, 1) (1, 0) (rank and index into plexFaceRemotes)
1297*3458b7b5SJames Wright // 1 | (0, 2) (0, 4) (1, 1)
1298*3458b7b5SJames Wright // 2 | (0, 3) (2, 2) (2, 0)
1299*3458b7b5SJames Wright // 3 | (1, 2) (2, 4)
1300*3458b7b5SJames Wright // 4 | (2, 1)
1301*3458b7b5SJames Wright // 5 | (2, 3)
1302*3458b7b5SJames Wright //
1303*3458b7b5SJames Wright // Note how at the leaves, the ranks are contiguous and in order
1304*3458b7b5SJames Wright PetscInt myrank_total_count;
1305*3458b7b5SJames Wright {
1306*3458b7b5SJames Wright PetscInt *rank_start, *rank_offset;
1307*3458b7b5SJames Wright
1308*3458b7b5SJames Wright PetscCall(PetscCalloc2(nranks, &rank_start, nranks, &rank_offset));
1309*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(local_rank_count, rank_start, nranks, MPIU_INT, MPI_SUM, comm));
1310*3458b7b5SJames Wright myrank_total_count = rank_start[myrank];
1311*3458b7b5SJames Wright PetscCall(PetscArrayzero(rank_start, nranks));
1312*3458b7b5SJames Wright PetscCallMPI(MPI_Exscan(local_rank_count, rank_start, nranks, MPIU_INT, MPI_SUM, comm));
1313*3458b7b5SJames Wright
1314*3458b7b5SJames Wright for (PetscInt r = 0; r < nPlexFaceRemotes; r++) {
1315*3458b7b5SJames Wright PetscInt rank = plexFaceRemotes[r].rank;
1316*3458b7b5SJames Wright plexFaceRemotes[r].index = rank_start[rank] + rank_offset[rank];
1317*3458b7b5SJames Wright rank_offset[rank]++;
1318*3458b7b5SJames Wright }
1319*3458b7b5SJames Wright PetscCall(PetscFree2(rank_start, rank_offset));
1320*3458b7b5SJames Wright }
1321*3458b7b5SJames Wright
1322*3458b7b5SJames Wright { // Communicate the leaves to roots and build cg2plexSF
1323*3458b7b5SJames Wright PetscSF plexRemotes2ownedRemotesSF;
1324*3458b7b5SJames Wright PetscSFNode *iremote_cg2plexSF;
1325*3458b7b5SJames Wright
1326*3458b7b5SJames Wright PetscCall(PetscSFCreate(comm, &plexRemotes2ownedRemotesSF));
1327*3458b7b5SJames Wright PetscCall(PetscSFSetGraph(plexRemotes2ownedRemotesSF, myrank_total_count, nPlexFaceRemotes, NULL, PETSC_COPY_VALUES, plexFaceRemotes, PETSC_OWN_POINTER));
1328*3458b7b5SJames Wright PetscCall(PetscMalloc1(myrank_total_count, &iremote_cg2plexSF));
1329*3458b7b5SJames Wright PetscCall(PetscSFViewFromOptions(plexRemotes2ownedRemotesSF, NULL, "-plex2ownedremotes_sf_view"));
1330*3458b7b5SJames Wright for (PetscInt i = 0; i < myrank_total_count; i++) iremote_cg2plexSF[i] = (PetscSFNode){.rank = -1, .index = -1};
1331*3458b7b5SJames Wright PetscCall(PetscSFReduceBegin(plexRemotes2ownedRemotesSF, MPIU_SF_NODE, ownedFaceRemotes, iremote_cg2plexSF, MPI_REPLACE));
1332*3458b7b5SJames Wright PetscCall(PetscSFReduceEnd(plexRemotes2ownedRemotesSF, MPIU_SF_NODE, ownedFaceRemotes, iremote_cg2plexSF, MPI_REPLACE));
1333*3458b7b5SJames Wright PetscCall(PetscSFDestroy(&plexRemotes2ownedRemotesSF));
1334*3458b7b5SJames Wright for (PetscInt i = 0; i < myrank_total_count; i++) PetscCheck(iremote_cg2plexSF[i].rank >= 0 && iremote_cg2plexSF[i].index != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Owned face SFNode was not reduced properly");
1335*3458b7b5SJames Wright
1336*3458b7b5SJames Wright PetscCall(PetscSFCreate(comm, cg2plexSF));
1337*3458b7b5SJames Wright PetscCall(PetscSFSetGraph(*cg2plexSF, fownedSize, myrank_total_count, NULL, PETSC_COPY_VALUES, iremote_cg2plexSF, PETSC_OWN_POINTER));
1338*3458b7b5SJames Wright
1339*3458b7b5SJames Wright PetscCall(PetscFree(ownedFaceRemotes));
1340*3458b7b5SJames Wright }
1341*3458b7b5SJames Wright
1342*3458b7b5SJames Wright PetscCall(PetscFree(local_rank_count));
1343*3458b7b5SJames Wright }
1344*3458b7b5SJames Wright
1345*3458b7b5SJames Wright PetscCall(PetscSectionDestroy(&fvert2mvertSection));
1346*3458b7b5SJames Wright PetscCall(PetscFree(uniq_face_verts));
1347*3458b7b5SJames Wright PetscCall(PetscFree(fvert2mvert));
1348*3458b7b5SJames Wright }
1349*3458b7b5SJames Wright
1350*3458b7b5SJames Wright { // -- Find plexFaces
1351*3458b7b5SJames Wright // Distribute owned-CGNS-face connectivity to the ranks which have corresponding Plex faces, and then find the corresponding Plex faces
1352*3458b7b5SJames Wright PetscSection connDistSection;
1353*3458b7b5SJames Wright PetscInt *connDist;
1354*3458b7b5SJames Wright
1355*3458b7b5SJames Wright // Distribute the face connectivity to the rank that has that face
1356*3458b7b5SJames Wright PetscCall(PetscSectionCreate(comm, &connDistSection));
1357*3458b7b5SJames Wright PetscCall(PetscSectionMigrateData(*cg2plexSF, MPIU_INT, connSection, conn, connDistSection, (void **)&connDist, NULL));
1358*3458b7b5SJames Wright
1359*3458b7b5SJames Wright { // Translate CGNS vertex numbering to local Plex numbering
1360*3458b7b5SJames Wright PetscInt *dmplex_verts, *uniq_verts_sorted;
1361*3458b7b5SJames Wright PetscInt connDistSize;
1362*3458b7b5SJames Wright
1363*3458b7b5SJames Wright PetscCall(PetscMalloc2(nuniq_verts, &dmplex_verts, nuniq_verts, &uniq_verts_sorted));
1364*3458b7b5SJames Wright PetscCall(PetscArraycpy(uniq_verts_sorted, uniq_verts, nuniq_verts));
1365*3458b7b5SJames Wright // uniq_verts are one-to-one with the DMPlex vertices with an offset, see DMPlexBuildFromCellListParallel()
1366*3458b7b5SJames Wright for (PetscInt v = 0; v < nuniq_verts; v++) dmplex_verts[v] = v + plex_vertex_offset;
1367*3458b7b5SJames Wright PetscCall(PetscSortIntWithArray(nuniq_verts, uniq_verts_sorted, dmplex_verts));
1368*3458b7b5SJames Wright
1369*3458b7b5SJames Wright PetscCall(PetscSectionGetStorageSize(connDistSection, &connDistSize));
1370*3458b7b5SJames Wright for (PetscInt v = 0; v < connDistSize; v++) {
1371*3458b7b5SJames Wright PetscInt idx;
1372*3458b7b5SJames Wright PetscCall(PetscFindInt(connDist[v], nuniq_verts, uniq_verts_sorted, &idx));
1373*3458b7b5SJames Wright PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find CGNS vertex id (from face connectivity) in local plex");
1374*3458b7b5SJames Wright connDist[v] = dmplex_verts[idx];
1375*3458b7b5SJames Wright }
1376*3458b7b5SJames Wright PetscCall(PetscFree2(dmplex_verts, uniq_verts_sorted));
1377*3458b7b5SJames Wright }
1378*3458b7b5SJames Wright
1379*3458b7b5SJames Wright // Debugging info
1380*3458b7b5SJames Wright PetscBool view_connectivity = PETSC_FALSE;
1381*3458b7b5SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_view_face_connectivity", &view_connectivity, NULL));
1382*3458b7b5SJames Wright if (view_connectivity) {
1383*3458b7b5SJames Wright PetscSection conesSection;
1384*3458b7b5SJames Wright PetscInt *cones;
1385*3458b7b5SJames Wright
1386*3458b7b5SJames Wright PetscCall(PetscPrintf(comm, "Distributed CGNS Face Connectivity (in Plex vertex numbering):\n"));
1387*3458b7b5SJames Wright PetscCall(PetscSectionArrayView(connDistSection, connDist, PETSC_INT, NULL));
1388*3458b7b5SJames Wright PetscCall(DMPlexGetCones(dm, &cones));
1389*3458b7b5SJames Wright PetscCall(DMPlexGetConeSection(dm, &conesSection));
1390*3458b7b5SJames Wright PetscCall(PetscPrintf(comm, "Plex Cones:\n"));
1391*3458b7b5SJames Wright PetscCall(PetscSectionArrayView(conesSection, cones, PETSC_INT, NULL));
1392*3458b7b5SJames Wright }
1393*3458b7b5SJames Wright
1394*3458b7b5SJames Wright // For every face in connDistSection, find the transitive support of a vertex in that face connectivity.
1395*3458b7b5SJames Wright // Loop through the faces of the transitive support and find the matching face
1396*3458b7b5SJames Wright PetscBT plex_face_found;
1397*3458b7b5SJames Wright PetscInt fplexStart, fplexEnd, vplexStart, vplexEnd;
1398*3458b7b5SJames Wright PetscInt fdistStart, fdistEnd, numfdist;
1399*3458b7b5SJames Wright PetscCall(DMPlexGetHeightStratum(dm, 1, &fplexStart, &fplexEnd));
1400*3458b7b5SJames Wright PetscCall(DMPlexGetDepthStratum(dm, 0, &vplexStart, &vplexEnd));
1401*3458b7b5SJames Wright PetscCall(PetscSectionGetChart(connDistSection, &fdistStart, &fdistEnd));
1402*3458b7b5SJames Wright numfdist = fdistEnd - fdistStart;
1403*3458b7b5SJames Wright PetscCall(PetscMalloc1(numfdist, plexFaces));
1404*3458b7b5SJames Wright PetscCall(PetscBTCreate(numfdist, &plex_face_found));
1405*3458b7b5SJames Wright for (PetscInt i = 0; i < numfdist; i++) (*plexFaces)[i] = -1;
1406*3458b7b5SJames Wright
1407*3458b7b5SJames Wright for (PetscInt f = fdistStart, f_i = 0; f < fdistEnd; f++, f_i++) {
1408*3458b7b5SJames Wright PetscInt ndof, offset, support_size;
1409*3458b7b5SJames Wright PetscInt *support = NULL;
1410*3458b7b5SJames Wright
1411*3458b7b5SJames Wright PetscCall(PetscSectionGetDof(connDistSection, f, &ndof));
1412*3458b7b5SJames Wright PetscCall(PetscSectionGetOffset(connDistSection, f, &offset));
1413*3458b7b5SJames Wright
1414*3458b7b5SJames Wright // Loop through transitive support of a vertex in the CGNS face connectivity
1415*3458b7b5SJames Wright PetscCall(DMPlexGetTransitiveClosure(dm, connDist[offset + 0], PETSC_FALSE, &support_size, &support));
1416*3458b7b5SJames Wright for (PetscInt s = 0; s < support_size; s++) {
1417*3458b7b5SJames Wright PetscInt face_point = support[s * 2]; // closure stores points and orientations, [p_0, o_0, p_1, o_1, ...]
1418*3458b7b5SJames Wright PetscInt trans_cone_size, *trans_cone = NULL;
1419*3458b7b5SJames Wright
1420*3458b7b5SJames Wright if (face_point < fplexStart || face_point >= fplexEnd) continue; // Skip non-face points
1421*3458b7b5SJames Wright // See if face_point has the same vertices
1422*3458b7b5SJames Wright PetscCall(DMPlexGetTransitiveClosure(dm, face_point, PETSC_TRUE, &trans_cone_size, &trans_cone));
1423*3458b7b5SJames Wright for (PetscInt c = 0; c < trans_cone_size; c++) {
1424*3458b7b5SJames Wright PetscInt vertex_point = trans_cone[c * 2], conn_has_vertex;
1425*3458b7b5SJames Wright if (vertex_point < vplexStart || vertex_point >= vplexEnd) continue; // Skip non-vertex points
1426*3458b7b5SJames Wright PetscCall(PetscFindIntUnsorted(vertex_point, ndof, &connDist[offset], &conn_has_vertex));
1427*3458b7b5SJames Wright if (conn_has_vertex < 0) goto check_next_face;
1428*3458b7b5SJames Wright }
1429*3458b7b5SJames Wright (*plexFaces)[f_i] = face_point;
1430*3458b7b5SJames Wright PetscCall(DMPlexRestoreTransitiveClosure(dm, face_point, PETSC_TRUE, &trans_cone_size, &trans_cone));
1431*3458b7b5SJames Wright break;
1432*3458b7b5SJames Wright check_next_face:
1433*3458b7b5SJames Wright PetscCall(DMPlexRestoreTransitiveClosure(dm, face_point, PETSC_TRUE, &trans_cone_size, &trans_cone));
1434*3458b7b5SJames Wright continue;
1435*3458b7b5SJames Wright }
1436*3458b7b5SJames Wright PetscCall(DMPlexRestoreTransitiveClosure(dm, connDist[offset + 0], PETSC_FALSE, &support_size, &support));
1437*3458b7b5SJames Wright if ((*plexFaces)[f_i] != -1) PetscCall(PetscBTSet(plex_face_found, f_i));
1438*3458b7b5SJames Wright }
1439*3458b7b5SJames Wright
1440*3458b7b5SJames Wright // Some distributed CGNS faces did not find a matching plex face
1441*3458b7b5SJames Wright // This can happen if a partition has all the faces surrounding a distributed CGNS face, but does not have the face itself (it's parent element is owned by a different partition).
1442*3458b7b5SJames Wright // Thus, the partition has the vertices associated with the CGNS face, but doesn't actually have the face itself.
1443*3458b7b5SJames Wright // For example, take the following quad mesh, where the numbers represent the owning rank and CGNS face ID.
1444*3458b7b5SJames Wright //
1445*3458b7b5SJames Wright // 2 3 4 <-- face ID
1446*3458b7b5SJames Wright // ----- ----- -----
1447*3458b7b5SJames Wright // | 0 | 1 | 0 | <-- rank
1448*3458b7b5SJames Wright // ----- ----- -----
1449*3458b7b5SJames Wright // 5 6 7 <-- face ID
1450*3458b7b5SJames Wright //
1451*3458b7b5SJames Wright // In this case, rank 0 will have all the vertices of face 3 and 6 in it's Plex, but does not actually have either face.
1452*3458b7b5SJames Wright //
1453*3458b7b5SJames Wright // To address this, we remove the leaves associated with these missing faces from cg2plexSF and then verify that all owned faces did find a matching plex face (e.g. root degree > 1)
1454*3458b7b5SJames Wright PetscCount num_plex_faces_found = PetscBTCountSet(plex_face_found, numfdist);
1455*3458b7b5SJames Wright PetscBool some_faces_not_found = num_plex_faces_found < numfdist;
1456*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &some_faces_not_found, 1, MPI_C_BOOL, MPI_LOR, comm));
1457*3458b7b5SJames Wright if (some_faces_not_found) {
1458*3458b7b5SJames Wright PetscSFNode *iremote_cg2plex_new;
1459*3458b7b5SJames Wright const PetscInt *root_degree;
1460*3458b7b5SJames Wright PetscInt num_roots, *plexFacesNew;
1461*3458b7b5SJames Wright
1462*3458b7b5SJames Wright PetscCall(PetscMalloc1(num_plex_faces_found, &iremote_cg2plex_new));
1463*3458b7b5SJames Wright PetscCall(PetscCalloc1(num_plex_faces_found, &plexFacesNew));
1464*3458b7b5SJames Wright { // Get SFNodes with matching faces
1465*3458b7b5SJames Wright const PetscSFNode *iremote_cg2plex_old;
1466*3458b7b5SJames Wright PetscInt num_leaves_old, n = 0;
1467*3458b7b5SJames Wright PetscCall(PetscSFGetGraph(*cg2plexSF, &num_roots, &num_leaves_old, NULL, &iremote_cg2plex_old));
1468*3458b7b5SJames Wright PetscAssert(num_roots == fownedSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent roots and owned faces.");
1469*3458b7b5SJames Wright PetscAssert(num_leaves_old == numfdist, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent leaves and distributed faces.");
1470*3458b7b5SJames Wright for (PetscInt o = 0; o < num_leaves_old; o++) {
1471*3458b7b5SJames Wright if (PetscBTLookupSet(plex_face_found, o)) {
1472*3458b7b5SJames Wright iremote_cg2plex_new[n] = iremote_cg2plex_old[o];
1473*3458b7b5SJames Wright plexFacesNew[n] = (*plexFaces)[o];
1474*3458b7b5SJames Wright n++;
1475*3458b7b5SJames Wright }
1476*3458b7b5SJames Wright }
1477*3458b7b5SJames Wright PetscAssert(n == num_plex_faces_found, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found %" PetscCount_FMT " matching plex faces, but only set %" PetscInt_FMT " SFNodes", num_plex_faces_found, n);
1478*3458b7b5SJames Wright }
1479*3458b7b5SJames Wright PetscCall(PetscSFSetGraph(*cg2plexSF, num_roots, num_plex_faces_found, NULL, PETSC_COPY_VALUES, iremote_cg2plex_new, PETSC_OWN_POINTER));
1480*3458b7b5SJames Wright
1481*3458b7b5SJames Wright // Verify that all CGNS faces have a matching Plex face on any rank
1482*3458b7b5SJames Wright PetscCall(PetscSFComputeDegreeBegin(*cg2plexSF, &root_degree));
1483*3458b7b5SJames Wright PetscCall(PetscSFComputeDegreeEnd(*cg2plexSF, &root_degree));
1484*3458b7b5SJames Wright for (PetscInt r = 0; r < num_roots; r++) {
1485*3458b7b5SJames Wright PetscCheck(root_degree[r] > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find plex face for the CGNS face %" PetscInt_FMT, face_ids[r]);
1486*3458b7b5SJames Wright PetscCheck(root_degree[r] == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Found more than one plex face for the CGNS face %" PetscInt_FMT ". Face may be internal rather than at mesh domain boundary", face_ids[r]);
1487*3458b7b5SJames Wright }
1488*3458b7b5SJames Wright
1489*3458b7b5SJames Wright if (PetscDefined(USE_DEBUG)) {
1490*3458b7b5SJames Wright for (PetscInt i = 0; i < num_plex_faces_found; i++)
1491*3458b7b5SJames Wright PetscCheck(plexFacesNew[i] >= fplexStart && plexFacesNew[i] < fplexEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Plex face ID %" PetscInt_FMT "outside of face stratum [%" PetscInt_FMT ", %" PetscInt_FMT ")", plexFacesNew[i], fplexStart, fplexEnd);
1492*3458b7b5SJames Wright }
1493*3458b7b5SJames Wright
1494*3458b7b5SJames Wright PetscCall(PetscFree(*plexFaces));
1495*3458b7b5SJames Wright *plexFaces = plexFacesNew;
1496*3458b7b5SJames Wright }
1497*3458b7b5SJames Wright
1498*3458b7b5SJames Wright PetscCall(PetscBTDestroy(&plex_face_found));
1499*3458b7b5SJames Wright PetscCall(PetscSectionDestroy(&connDistSection));
1500*3458b7b5SJames Wright PetscCall(PetscFree(connDist));
1501*3458b7b5SJames Wright }
1502*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
1503*3458b7b5SJames Wright }
1504*3458b7b5SJames Wright
1505*3458b7b5SJames Wright // Copied from PetscOptionsStringToInt
PetscStrtoInt(const char name[],PetscInt * a)1506*3458b7b5SJames Wright static inline PetscErrorCode PetscStrtoInt(const char name[], PetscInt *a)
1507*3458b7b5SJames Wright {
1508*3458b7b5SJames Wright size_t len;
1509*3458b7b5SJames Wright char *endptr;
1510*3458b7b5SJames Wright long strtolval;
1511*3458b7b5SJames Wright
1512*3458b7b5SJames Wright PetscFunctionBegin;
1513*3458b7b5SJames Wright PetscCall(PetscStrlen(name, &len));
1514*3458b7b5SJames Wright PetscCheck(len, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "character string of length zero has no numerical value");
1515*3458b7b5SJames Wright
1516*3458b7b5SJames Wright strtolval = strtol(name, &endptr, 10);
1517*3458b7b5SJames Wright PetscCheck((size_t)(endptr - name) == len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input string \"%s\" has no integer value (do not include . in it)", name);
1518*3458b7b5SJames Wright
1519*3458b7b5SJames Wright #if defined(PETSC_USE_64BIT_INDICES) && defined(PETSC_HAVE_ATOLL)
1520*3458b7b5SJames Wright (void)strtolval;
1521*3458b7b5SJames Wright *a = atoll(name);
1522*3458b7b5SJames Wright #elif defined(PETSC_USE_64BIT_INDICES) && defined(PETSC_HAVE___INT64)
1523*3458b7b5SJames Wright (void)strtolval;
1524*3458b7b5SJames Wright *a = _atoi64(name);
1525*3458b7b5SJames Wright #else
1526*3458b7b5SJames Wright *a = (PetscInt)strtolval;
1527*3458b7b5SJames Wright #endif
1528*3458b7b5SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
1529*3458b7b5SJames Wright }
1530*3458b7b5SJames Wright
1531*3458b7b5SJames Wright typedef struct {
1532*3458b7b5SJames Wright char name[CGIO_MAX_NAME_LENGTH + 1];
1533*3458b7b5SJames Wright int normal[3], ndatasets;
1534*3458b7b5SJames Wright cgsize_t npoints, nnormals;
1535*3458b7b5SJames Wright CGNS_ENUMT(BCType_t) bctype;
1536*3458b7b5SJames Wright CGNS_ENUMT(DataType_t) normal_datatype;
1537*3458b7b5SJames Wright CGNS_ENUMT(PointSetType_t) pointtype;
1538*3458b7b5SJames Wright } CGBCInfo;
1539*3458b7b5SJames Wright
DMPlexCreateCGNS_Internal_Parallel(MPI_Comm comm,PetscInt cgid,PetscBool interpolate,DM * dm)1540472b9844SJames Wright PetscErrorCode DMPlexCreateCGNS_Internal_Parallel(MPI_Comm comm, PetscInt cgid, PetscBool interpolate, DM *dm)
1541472b9844SJames Wright {
1542472b9844SJames Wright PetscMPIInt num_proc, rank;
1543472b9844SJames Wright /* Read from file */
1544472b9844SJames Wright char basename[CGIO_MAX_NAME_LENGTH + 1];
1545472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1];
1546472b9844SJames Wright int dim = 0, physDim = 0, coordDim = 0;
1547472b9844SJames Wright PetscInt NVertices = 0, NCells = 0;
1548472b9844SJames Wright int nzones = 0, nbases;
1549b30057acSJames Wright int zone = 1; // Only supports single zone files
1550b30057acSJames Wright int base = 1; // Only supports single base
1551472b9844SJames Wright
1552472b9844SJames Wright PetscFunctionBegin;
1553472b9844SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank));
1554472b9844SJames Wright PetscCallMPI(MPI_Comm_size(comm, &num_proc));
1555472b9844SJames Wright PetscCall(DMCreate(comm, dm));
1556472b9844SJames Wright PetscCall(DMSetType(*dm, DMPLEX));
1557472b9844SJames Wright
15584c155f28SJames Wright PetscCallCGNSRead(cg_nbases(cgid, &nbases), *dm, 0);
1559472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases);
1560f605775fSPierre Jolivet // From the CGNS web page cell_dim phys_dim (embedding space in PETSc) CGNS defines as length of spatial vectors/components)
1561b30057acSJames Wright PetscCallCGNSRead(cg_base_read(cgid, base, basename, &dim, &physDim), *dm, 0);
1562b30057acSJames Wright PetscCallCGNSRead(cg_nzones(cgid, base, &nzones), *dm, 0);
1563472b9844SJames Wright PetscCheck(nzones == 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Parallel reader limited to one zone, not %d", nzones);
1564472b9844SJames Wright {
1565472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */
1566472b9844SJames Wright
1567b30057acSJames Wright PetscCallCGNSRead(cg_zone_read(cgid, base, zone, buffer, sizes), *dm, 0);
1568472b9844SJames Wright NVertices = sizes[0];
1569472b9844SJames Wright NCells = sizes[1];
1570472b9844SJames Wright }
1571472b9844SJames Wright
1572472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)*dm, basename));
1573472b9844SJames Wright PetscCall(DMSetDimension(*dm, dim));
1574472b9844SJames Wright coordDim = dim;
1575472b9844SJames Wright
1576472b9844SJames Wright // This is going to be a headache for mixed-topology and multiple sections. We may have to restore reading the data twice (once before the SetChart
1577472b9844SJames Wright // call to get this right but continuing for now with single section, single topology, one zone.
1578472b9844SJames Wright // establish element ranges for my rank
1579472b9844SJames Wright PetscInt mystarte, myende, mystartv, myendv, myownede, myownedv;
1580472b9844SJames Wright PetscLayout elem_map, vtx_map;
1581472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NCells, 1, &elem_map));
1582472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NVertices, 1, &vtx_map));
1583472b9844SJames Wright PetscCall(PetscLayoutGetRange(elem_map, &mystarte, &myende));
1584472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(elem_map, &myownede));
1585472b9844SJames Wright PetscCall(PetscLayoutGetRange(vtx_map, &mystartv, &myendv));
1586472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(vtx_map, &myownedv));
1587472b9844SJames Wright
1588472b9844SJames Wright // -- Build Plex in parallel
1589f1a88294SStefano Zampini DMPolytopeType dm_cell_type = DM_POLYTOPE_UNKNOWN;
1590472b9844SJames Wright PetscInt pOrder = 1, numClosure = -1;
1591*3458b7b5SJames Wright cgsize_t *elements = NULL;
1592*3458b7b5SJames Wright int *face_section_ids, *cell_section_ids, num_face_sections = 0, num_cell_sections = 0;
1593*3458b7b5SJames Wright PetscInt *uniq_verts, nuniq_verts;
1594472b9844SJames Wright {
1595472b9844SJames Wright int nsections;
1596472b9844SJames Wright PetscInt *elementsQ1, numCorners = -1;
1597472b9844SJames Wright const int *perm;
1598472b9844SJames Wright cgsize_t start, end; // Throwaway
1599472b9844SJames Wright
1600b30057acSJames Wright cg_nsections(cgid, base, zone, &nsections);
1601*3458b7b5SJames Wright PetscCall(PetscMalloc2(nsections, &face_section_ids, nsections, &cell_section_ids));
1602472b9844SJames Wright // Read element connectivity
1603472b9844SJames Wright for (int index_sect = 1; index_sect <= nsections; index_sect++) {
1604472b9844SJames Wright int nbndry, parentFlag;
1605472b9844SJames Wright PetscInt cell_dim;
1606472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType;
1607472b9844SJames Wright
1608b30057acSJames Wright PetscCallCGNSRead(cg_section_read(cgid, base, zone, index_sect, buffer, &cellType, &start, &end, &nbndry, &parentFlag), *dm, 0);
1609472b9844SJames Wright
1610472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, &dm_cell_type, &numCorners, &cell_dim));
1611472b9844SJames Wright // Skip over element that are not max dimension (ie. boundary elements)
1612*3458b7b5SJames Wright if (cell_dim == dim) cell_section_ids[num_cell_sections++] = index_sect;
1613*3458b7b5SJames Wright else if (cell_dim == dim - 1) face_section_ids[num_face_sections++] = index_sect;
1614*3458b7b5SJames Wright }
1615*3458b7b5SJames Wright PetscCheck(num_cell_sections == 1, comm, PETSC_ERR_SUP, "CGNS Reader does not support more than 1 full-dimension cell section");
1616*3458b7b5SJames Wright
1617*3458b7b5SJames Wright {
1618*3458b7b5SJames Wright int index_sect = cell_section_ids[0], nbndry, parentFlag;
1619*3458b7b5SJames Wright CGNS_ENUMT(ElementType_t) cellType;
1620*3458b7b5SJames Wright
1621*3458b7b5SJames Wright PetscCallCGNSRead(cg_section_read(cgid, base, zone, index_sect, buffer, &cellType, &start, &end, &nbndry, &parentFlag), *dm, 0);
1622472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, &numClosure, &pOrder));
1623472b9844SJames Wright PetscCall(PetscMalloc1(myownede * numClosure, &elements));
1624b30057acSJames Wright PetscCallCGNSReadData(cgp_elements_read_data(cgid, base, zone, index_sect, mystarte + 1, myende, elements), *dm, 0);
1625472b9844SJames Wright for (PetscInt v = 0; v < myownede * numClosure; ++v) elements[v] -= 1; // 0 based
1626472b9844SJames Wright
1627472b9844SJames Wright // Create corners-only connectivity
1628*3458b7b5SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, &dm_cell_type, &numCorners, NULL));
1629472b9844SJames Wright PetscCall(PetscMalloc1(myownede * numCorners, &elementsQ1));
1630472b9844SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numCorners, NULL, &perm));
1631472b9844SJames Wright for (PetscInt e = 0; e < myownede; ++e) {
1632472b9844SJames Wright for (PetscInt v = 0; v < numCorners; ++v) elementsQ1[e * numCorners + perm[v]] = elements[e * numClosure + v];
1633472b9844SJames Wright }
1634*3458b7b5SJames Wright }
1635472b9844SJames Wright
1636472b9844SJames Wright // Build cell-vertex Plex
1637*3458b7b5SJames Wright PetscCall(DMPlexBuildFromCellListParallel(*dm, myownede, myownedv, NVertices, numCorners, elementsQ1, NULL, &uniq_verts));
1638472b9844SJames Wright PetscCall(DMViewFromOptions(*dm, NULL, "-corner_dm_view"));
1639*3458b7b5SJames Wright {
1640*3458b7b5SJames Wright PetscInt pStart, pEnd;
1641*3458b7b5SJames Wright PetscCall(DMPlexGetChart(*dm, &pStart, &pEnd));
1642*3458b7b5SJames Wright nuniq_verts = (pEnd - pStart) - myownede;
1643*3458b7b5SJames Wright }
1644472b9844SJames Wright PetscCall(PetscFree(elementsQ1));
1645472b9844SJames Wright }
1646472b9844SJames Wright
164701432a30SJames Wright if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(*dm));
1648472b9844SJames Wright
1649472b9844SJames Wright // -- Create SF for naive nodal-data read to elements
1650472b9844SJames Wright PetscSF plex_to_cgns_sf;
1651472b9844SJames Wright {
1652472b9844SJames Wright PetscInt nleaves, num_comp;
1653472b9844SJames Wright PetscInt *leaf, num_leaves = 0;
1654472b9844SJames Wright PetscInt cStart, cEnd;
1655472b9844SJames Wright const int *perm;
1656472b9844SJames Wright PetscSF cgns_to_local_sf;
1657472b9844SJames Wright PetscSection local_section;
1658472b9844SJames Wright PetscFE fe;
1659472b9844SJames Wright
1660472b9844SJames Wright // sfNatural requires PetscSection to handle DMDistribute, so we use PetscFE to define the section
1661472b9844SJames Wright // Use number of components = 1 to work with just the nodes themselves
1662472b9844SJames Wright PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, dm_cell_type, pOrder, PETSC_DETERMINE, &fe));
1663472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)fe, "FE for sfNatural"));
1664472b9844SJames Wright PetscCall(DMAddField(*dm, NULL, (PetscObject)fe));
1665472b9844SJames Wright PetscCall(DMCreateDS(*dm));
1666472b9844SJames Wright PetscCall(PetscFEDestroy(&fe));
1667472b9844SJames Wright
1668472b9844SJames Wright PetscCall(DMGetLocalSection(*dm, &local_section));
1669472b9844SJames Wright PetscCall(PetscSectionViewFromOptions(local_section, NULL, "-fe_natural_section_view"));
1670472b9844SJames Wright PetscCall(PetscSectionGetFieldComponents(local_section, 0, &num_comp));
1671472b9844SJames Wright PetscCall(PetscSectionGetStorageSize(local_section, &nleaves));
1672472b9844SJames Wright nleaves /= num_comp;
1673472b9844SJames Wright PetscCall(PetscMalloc1(nleaves, &leaf));
1674472b9844SJames Wright for (PetscInt i = 0; i < nleaves; i++) leaf[i] = -1;
1675472b9844SJames Wright
1676472b9844SJames Wright // Get the permutation from CGNS closure numbering to PLEX closure numbering
1677472b9844SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numClosure, NULL, &perm));
1678472b9844SJames Wright PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd));
1679472b9844SJames Wright for (PetscInt cell = cStart; cell < cEnd; ++cell) {
1680472b9844SJames Wright PetscInt num_closure_dof, *closure_idx = NULL;
1681472b9844SJames Wright
1682472b9844SJames Wright PetscCall(DMPlexGetClosureIndices(*dm, local_section, local_section, cell, PETSC_FALSE, &num_closure_dof, &closure_idx, NULL, NULL));
1683472b9844SJames Wright PetscAssert(numClosure * num_comp == num_closure_dof, comm, PETSC_ERR_PLIB, "Closure dof size does not match polytope");
1684472b9844SJames Wright for (PetscInt i = 0; i < numClosure; i++) {
1685472b9844SJames Wright PetscInt li = closure_idx[perm[i] * num_comp] / num_comp;
1686472b9844SJames Wright if (li < 0) continue;
1687472b9844SJames Wright
1688472b9844SJames Wright PetscInt cgns_idx = elements[cell * numClosure + i];
1689472b9844SJames Wright if (leaf[li] == -1) {
1690472b9844SJames Wright leaf[li] = cgns_idx;
1691472b9844SJames Wright num_leaves++;
1692472b9844SJames Wright } else PetscAssert(leaf[li] == cgns_idx, PETSC_COMM_SELF, PETSC_ERR_PLIB, "leaf does not match previously set");
1693472b9844SJames Wright }
1694472b9844SJames Wright PetscCall(DMPlexRestoreClosureIndices(*dm, local_section, local_section, cell, PETSC_FALSE, &num_closure_dof, &closure_idx, NULL, NULL));
1695472b9844SJames Wright }
1696472b9844SJames Wright PetscAssert(num_leaves == nleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "leaf count in closure does not match nleaves");
1697472b9844SJames Wright PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)*dm), &cgns_to_local_sf));
1698472b9844SJames Wright PetscCall(PetscSFSetGraphLayout(cgns_to_local_sf, vtx_map, nleaves, NULL, PETSC_USE_POINTER, leaf));
1699472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)cgns_to_local_sf, "CGNS to Plex SF"));
1700472b9844SJames Wright PetscCall(PetscSFViewFromOptions(cgns_to_local_sf, NULL, "-CGNStoPlex_sf_view"));
1701472b9844SJames Wright PetscCall(PetscFree(leaf));
1702472b9844SJames Wright PetscCall(PetscFree(elements));
1703472b9844SJames Wright
1704472b9844SJames Wright { // Convert cgns_to_local to global_to_cgns
1705472b9844SJames Wright PetscSF sectionsf, cgns_to_global_sf;
1706472b9844SJames Wright
1707472b9844SJames Wright PetscCall(DMGetSectionSF(*dm, §ionsf));
1708472b9844SJames Wright PetscCall(PetscSFComposeInverse(cgns_to_local_sf, sectionsf, &cgns_to_global_sf));
1709472b9844SJames Wright PetscCall(PetscSFDestroy(&cgns_to_local_sf));
1710472b9844SJames Wright PetscCall(PetscSFCreateInverseSF(cgns_to_global_sf, &plex_to_cgns_sf));
1711472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)plex_to_cgns_sf, "Global Plex to CGNS"));
1712472b9844SJames Wright PetscCall(PetscSFDestroy(&cgns_to_global_sf));
1713472b9844SJames Wright }
1714472b9844SJames Wright }
1715472b9844SJames Wright
1716472b9844SJames Wright { // -- Set coordinates for DM
1717472b9844SJames Wright PetscScalar *coords;
1718472b9844SJames Wright float *x[3];
1719472b9844SJames Wright double *xd[3];
1720472b9844SJames Wright PetscBool read_with_double;
1721472b9844SJames Wright PetscFE cfe;
1722472b9844SJames Wright
1723472b9844SJames Wright // Setup coordinate space first. Use pOrder here for isoparametric; revisit with CPEX-0045 High Order.
1724472b9844SJames Wright PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, coordDim, dm_cell_type, pOrder, PETSC_DETERMINE, &cfe));
17254c712d99Sksagiyam PetscCall(DMSetCoordinateDisc(*dm, cfe, PETSC_FALSE, PETSC_FALSE));
1726472b9844SJames Wright PetscCall(PetscFEDestroy(&cfe));
1727472b9844SJames Wright
1728472b9844SJames Wright { // Determine if coords are written in single or double precision
1729472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype;
1730472b9844SJames Wright
1731b30057acSJames Wright PetscCallCGNSRead(cg_coord_info(cgid, base, zone, 1, &datatype, buffer), *dm, 0);
17325582b114SJames Wright read_with_double = datatype == CGNS_ENUMV(RealDouble) ? PETSC_TRUE : PETSC_FALSE;
1733472b9844SJames Wright }
1734472b9844SJames Wright
1735472b9844SJames Wright // Read coords from file and set into component-major ordering
1736472b9844SJames Wright if (read_with_double) PetscCall(PetscMalloc3(myownedv, &xd[0], myownedv, &xd[1], myownedv, &xd[2]));
1737472b9844SJames Wright else PetscCall(PetscMalloc3(myownedv, &x[0], myownedv, &x[1], myownedv, &x[2]));
1738472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * coordDim, &coords));
1739472b9844SJames Wright {
1740472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */
1741472b9844SJames Wright cgsize_t range_min[3] = {mystartv + 1, 1, 1};
1742472b9844SJames Wright cgsize_t range_max[3] = {myendv, 1, 1};
1743472b9844SJames Wright int ngrids, ncoords;
1744472b9844SJames Wright
1745b30057acSJames Wright PetscCallCGNSRead(cg_zone_read(cgid, base, zone, buffer, sizes), *dm, 0);
1746b30057acSJames Wright PetscCallCGNSRead(cg_ngrids(cgid, base, zone, &ngrids), *dm, 0);
1747472b9844SJames Wright PetscCheck(ngrids <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single grid, not %d", ngrids);
1748b30057acSJames Wright PetscCallCGNSRead(cg_ncoords(cgid, base, zone, &ncoords), *dm, 0);
1749472b9844SJames Wright PetscCheck(ncoords == coordDim, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a coordinate array for each dimension, not %d", ncoords);
1750472b9844SJames Wright if (read_with_double) {
1751b30057acSJames Wright for (int d = 0; d < coordDim; ++d) PetscCallCGNSReadData(cgp_coord_read_data(cgid, base, zone, (d + 1), range_min, range_max, xd[d]), *dm, 0);
1752472b9844SJames Wright if (coordDim >= 1) {
1753472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 0] = xd[0][v];
1754472b9844SJames Wright }
1755472b9844SJames Wright if (coordDim >= 2) {
1756472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 1] = xd[1][v];
1757472b9844SJames Wright }
1758472b9844SJames Wright if (coordDim >= 3) {
1759472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 2] = xd[2][v];
1760472b9844SJames Wright }
1761472b9844SJames Wright } else {
1762b30057acSJames Wright for (int d = 0; d < coordDim; ++d) PetscCallCGNSReadData(cgp_coord_read_data(cgid, 1, zone, (d + 1), range_min, range_max, x[d]), *dm, 0);
1763472b9844SJames Wright if (coordDim >= 1) {
1764472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 0] = x[0][v];
1765472b9844SJames Wright }
1766472b9844SJames Wright if (coordDim >= 2) {
1767472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 1] = x[1][v];
1768472b9844SJames Wright }
1769472b9844SJames Wright if (coordDim >= 3) {
1770472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 2] = x[2][v];
1771472b9844SJames Wright }
1772472b9844SJames Wright }
1773472b9844SJames Wright }
1774472b9844SJames Wright if (read_with_double) PetscCall(PetscFree3(xd[0], xd[1], xd[2]));
1775472b9844SJames Wright else PetscCall(PetscFree3(x[0], x[1], x[2]));
1776472b9844SJames Wright
1777472b9844SJames Wright { // Reduce CGNS-ordered coordinate nodes to Plex ordering, and set DM's coordinates
1778472b9844SJames Wright Vec coord_global;
1779472b9844SJames Wright MPI_Datatype unit;
1780472b9844SJames Wright PetscScalar *coord_global_array;
1781472b9844SJames Wright DM cdm;
1782472b9844SJames Wright
1783472b9844SJames Wright PetscCall(DMGetCoordinateDM(*dm, &cdm));
1784472b9844SJames Wright PetscCall(DMCreateGlobalVector(cdm, &coord_global));
1785472b9844SJames Wright PetscCall(VecGetArrayWrite(coord_global, &coord_global_array));
1786472b9844SJames Wright PetscCallMPI(MPI_Type_contiguous(coordDim, MPIU_SCALAR, &unit));
1787472b9844SJames Wright PetscCallMPI(MPI_Type_commit(&unit));
1788472b9844SJames Wright PetscCall(PetscSFReduceBegin(plex_to_cgns_sf, unit, coords, coord_global_array, MPI_REPLACE));
1789472b9844SJames Wright PetscCall(PetscSFReduceEnd(plex_to_cgns_sf, unit, coords, coord_global_array, MPI_REPLACE));
1790472b9844SJames Wright PetscCall(VecRestoreArrayWrite(coord_global, &coord_global_array));
1791472b9844SJames Wright PetscCallMPI(MPI_Type_free(&unit));
1792472b9844SJames Wright PetscCall(DMSetCoordinates(*dm, coord_global));
1793472b9844SJames Wright PetscCall(VecDestroy(&coord_global));
1794472b9844SJames Wright }
1795472b9844SJames Wright PetscCall(PetscFree(coords));
1796472b9844SJames Wright }
1797472b9844SJames Wright
1798*3458b7b5SJames Wright PetscCall(DMViewFromOptions(*dm, NULL, "-corner_interpolated_dm_view"));
1799*3458b7b5SJames Wright
1800*3458b7b5SJames Wright int nbocos;
1801*3458b7b5SJames Wright PetscCallCGNSRead(cg_nbocos(cgid, base, zone, &nbocos), *dm, 0);
1802*3458b7b5SJames Wright // In order to extract boundary condition (boco) information into DMLabels, each rank holds:
1803*3458b7b5SJames Wright // - The local Plex
1804*3458b7b5SJames Wright // - Naively read CGNS face connectivity
1805*3458b7b5SJames Wright // - Naively read list of CGNS faces for each boco
1806*3458b7b5SJames Wright //
1807*3458b7b5SJames Wright // First, we need to build a mapping from the CGNS faces to the (probably off-rank) Plex face.
1808*3458b7b5SJames Wright // The CGNS faces that each rank owns is known globally via cgnsLayouts.
1809*3458b7b5SJames Wright // The cg2plexSF maps these CGNS face IDs to their (probably off-rank) Plex face.
1810*3458b7b5SJames Wright // The plexFaces array maps the (contiguous) leaves of cg2plexSF to the local Plex face point.
1811*3458b7b5SJames Wright //
1812*3458b7b5SJames Wright // Next, we read the list of CGNS faces for each boco and find the location of that face's owner using cgnsLayouts.
1813*3458b7b5SJames Wright // Then, we can communicate the label value to the local Plex which corresponds to the CGNS face.
1814*3458b7b5SJames Wright if (interpolate && num_face_sections != 0 && nbocos != 0) {
1815*3458b7b5SJames Wright PetscSection connSection;
1816*3458b7b5SJames Wright PetscInt nCgFaces, nPlexFaces;
1817*3458b7b5SJames Wright PetscInt *face_ids, *conn, *plexFaces;
1818*3458b7b5SJames Wright PetscSF cg2plexSF;
1819*3458b7b5SJames Wright PetscLayout *cgnsLayouts;
1820*3458b7b5SJames Wright
1821*3458b7b5SJames Wright PetscCall(DMPlexCGNS_CreateCornersConnectivitySection(*dm, cgid, base, zone, num_face_sections, face_section_ids, &connSection, NULL, &face_ids, &cgnsLayouts, &conn));
1822*3458b7b5SJames Wright {
1823*3458b7b5SJames Wright PetscBool view_connectivity = PETSC_FALSE;
1824*3458b7b5SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_view_face_connectivity", &view_connectivity, NULL));
1825*3458b7b5SJames Wright if (view_connectivity) PetscCall(PetscSectionArrayView(connSection, conn, PETSC_INT, NULL));
1826*3458b7b5SJames Wright }
1827*3458b7b5SJames Wright PetscCall(DMPlexCGNS_MatchCGNSFacesToPlexFaces(*dm, nuniq_verts, uniq_verts, myownede, NVertices, connSection, face_ids, conn, &cg2plexSF, &plexFaces));
1828*3458b7b5SJames Wright PetscCall(PetscSFGetGraph(cg2plexSF, NULL, &nPlexFaces, NULL, NULL));
1829*3458b7b5SJames Wright {
1830*3458b7b5SJames Wright PetscInt start, end;
1831*3458b7b5SJames Wright PetscCall(PetscSectionGetChart(connSection, &start, &end));
1832*3458b7b5SJames Wright nCgFaces = end - start;
1833*3458b7b5SJames Wright }
1834*3458b7b5SJames Wright
1835*3458b7b5SJames Wright PetscInt *plexFaceValues, *cgFaceValues;
1836*3458b7b5SJames Wright PetscCall(PetscMalloc2(nPlexFaces, &plexFaceValues, nCgFaces, &cgFaceValues));
1837*3458b7b5SJames Wright for (PetscInt BC = 1; BC <= nbocos; BC++) {
1838*3458b7b5SJames Wright cgsize_t *points;
1839*3458b7b5SJames Wright CGBCInfo bcinfo;
1840*3458b7b5SJames Wright PetscBool is_faceset = PETSC_FALSE;
1841*3458b7b5SJames Wright PetscInt label_value = 1;
1842*3458b7b5SJames Wright
1843*3458b7b5SJames Wright PetscCallCGNSRead(cg_boco_info(cgid, base, zone, BC, bcinfo.name, &bcinfo.bctype, &bcinfo.pointtype, &bcinfo.npoints, bcinfo.normal, &bcinfo.nnormals, &bcinfo.normal_datatype, &bcinfo.ndatasets), *dm, 0);
1844*3458b7b5SJames Wright
1845*3458b7b5SJames Wright PetscCall(PetscStrbeginswith(bcinfo.name, "FaceSet", &is_faceset));
1846*3458b7b5SJames Wright if (is_faceset) {
1847*3458b7b5SJames Wright size_t faceset_len;
1848*3458b7b5SJames Wright PetscCall(PetscStrlen("FaceSet", &faceset_len));
1849*3458b7b5SJames Wright PetscCall(PetscStrtoInt(bcinfo.name + faceset_len, &label_value));
1850*3458b7b5SJames Wright }
1851*3458b7b5SJames Wright const char *label_name = is_faceset ? "Face Sets" : bcinfo.name;
1852*3458b7b5SJames Wright
1853*3458b7b5SJames Wright if (bcinfo.npoints < 1) continue;
1854*3458b7b5SJames Wright
1855*3458b7b5SJames Wright PetscLayout bc_layout;
1856*3458b7b5SJames Wright PetscInt bcStart, bcEnd, bcSize;
1857*3458b7b5SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, bcinfo.npoints, 1, &bc_layout));
1858*3458b7b5SJames Wright PetscCall(PetscLayoutGetRange(bc_layout, &bcStart, &bcEnd));
1859*3458b7b5SJames Wright PetscCall(PetscLayoutGetLocalSize(bc_layout, &bcSize));
1860*3458b7b5SJames Wright PetscCall(PetscLayoutDestroy(&bc_layout));
1861*3458b7b5SJames Wright PetscCall(DMGetWorkArray(*dm, bcSize, MPIU_CGSIZE, &points));
1862*3458b7b5SJames Wright
1863*3458b7b5SJames Wright const char *labels[] = {"Zone_t", "ZoneBC_t", "BC_t", "PointList"};
1864*3458b7b5SJames Wright PetscCallCGNSRead(cg_golist(cgid, base, 4, (char **)labels, (int[]){zone, 1, BC, 0}), *dm, 0);
1865*3458b7b5SJames Wright PetscCallCGNSReadData(cgp_ptlist_read_data(cgid, bcStart + 1, bcEnd, points), *dm, 0);
1866*3458b7b5SJames Wright
1867*3458b7b5SJames Wright PetscInt *label_values;
1868*3458b7b5SJames Wright PetscSFNode *remotes;
1869*3458b7b5SJames Wright PetscCall(PetscMalloc2(bcSize, &remotes, bcSize, &label_values));
1870*3458b7b5SJames Wright for (PetscInt p = 0; p < bcSize; p++) {
1871*3458b7b5SJames Wright PetscMPIInt bcrank;
1872*3458b7b5SJames Wright PetscInt bcidx;
1873*3458b7b5SJames Wright
1874*3458b7b5SJames Wright PetscCall(PetscLayoutFindOwnerIndex_CGNSSectionLayouts(cgnsLayouts, num_face_sections, points[p], &bcrank, &bcidx, NULL));
1875*3458b7b5SJames Wright remotes[p].rank = bcrank;
1876*3458b7b5SJames Wright remotes[p].index = bcidx;
1877*3458b7b5SJames Wright label_values[p] = label_value;
1878*3458b7b5SJames Wright }
1879*3458b7b5SJames Wright PetscCall(DMRestoreWorkArray(*dm, bcSize, MPIU_CGSIZE, &points));
1880*3458b7b5SJames Wright
1881*3458b7b5SJames Wright { // Communicate the BC values to their Plex-face owners
1882*3458b7b5SJames Wright PetscSF cg2bcSF;
1883*3458b7b5SJames Wright DMLabel label;
1884*3458b7b5SJames Wright
1885*3458b7b5SJames Wright for (PetscInt i = 0; i < nCgFaces; i++) cgFaceValues[i] = -1;
1886*3458b7b5SJames Wright for (PetscInt i = 0; i < nPlexFaces; i++) plexFaceValues[i] = -1;
1887*3458b7b5SJames Wright
1888*3458b7b5SJames Wright PetscCall(PetscSFCreate(comm, &cg2bcSF));
1889*3458b7b5SJames Wright PetscCall(PetscSFSetGraph(cg2bcSF, nCgFaces, bcSize, NULL, PETSC_COPY_VALUES, remotes, PETSC_USE_POINTER));
1890*3458b7b5SJames Wright
1891*3458b7b5SJames Wright PetscCall(PetscSFReduceBegin(cg2bcSF, MPIU_INT, label_values, cgFaceValues, MPI_REPLACE));
1892*3458b7b5SJames Wright PetscCall(PetscSFReduceEnd(cg2bcSF, MPIU_INT, label_values, cgFaceValues, MPI_REPLACE));
1893*3458b7b5SJames Wright PetscCall(PetscSFBcastBegin(cg2plexSF, MPIU_INT, cgFaceValues, plexFaceValues, MPI_REPLACE));
1894*3458b7b5SJames Wright PetscCall(PetscSFBcastEnd(cg2plexSF, MPIU_INT, cgFaceValues, plexFaceValues, MPI_REPLACE));
1895*3458b7b5SJames Wright PetscCall(PetscSFDestroy(&cg2bcSF));
1896*3458b7b5SJames Wright PetscCall(PetscFree2(remotes, label_values));
1897*3458b7b5SJames Wright
1898*3458b7b5SJames Wright // Set the label values for the communicated faces
1899*3458b7b5SJames Wright PetscCall(DMGetLabel(*dm, label_name, &label));
1900*3458b7b5SJames Wright if (label == NULL) {
1901*3458b7b5SJames Wright PetscCall(DMCreateLabel(*dm, label_name));
1902*3458b7b5SJames Wright PetscCall(DMGetLabel(*dm, label_name, &label));
1903*3458b7b5SJames Wright }
1904*3458b7b5SJames Wright for (PetscInt i = 0; i < nPlexFaces; i++) {
1905*3458b7b5SJames Wright if (plexFaceValues[i] == -1) continue;
1906*3458b7b5SJames Wright PetscCall(DMLabelSetValue(label, plexFaces[i], plexFaceValues[i]));
1907*3458b7b5SJames Wright }
1908*3458b7b5SJames Wright }
1909*3458b7b5SJames Wright }
1910*3458b7b5SJames Wright PetscCall(PetscFree2(plexFaceValues, cgFaceValues));
1911*3458b7b5SJames Wright PetscCall(PetscFree(plexFaces));
1912*3458b7b5SJames Wright PetscCall(PetscSFDestroy(&cg2plexSF));
1913*3458b7b5SJames Wright PetscCall(PetscFree(conn));
1914*3458b7b5SJames Wright for (PetscInt s = 0; s < num_face_sections; s++) PetscCall(PetscLayoutDestroy(&cgnsLayouts[s]));
1915*3458b7b5SJames Wright PetscCall(PetscSectionDestroy(&connSection));
1916*3458b7b5SJames Wright PetscCall(PetscFree(cgnsLayouts));
1917*3458b7b5SJames Wright PetscCall(PetscFree(face_ids));
1918*3458b7b5SJames Wright }
1919*3458b7b5SJames Wright PetscCall(PetscFree(uniq_verts));
1920*3458b7b5SJames Wright PetscCall(PetscFree2(face_section_ids, cell_section_ids));
1921*3458b7b5SJames Wright
1922472b9844SJames Wright // -- Set sfNatural for solution vectors in CGNS file
1923472b9844SJames Wright // NOTE: We set sfNatural to be the map between the original CGNS ordering of nodes and the Plex ordering of nodes.
1924472b9844SJames Wright PetscCall(PetscSFViewFromOptions(plex_to_cgns_sf, NULL, "-sfNatural_init_view"));
1925472b9844SJames Wright PetscCall(DMSetNaturalSF(*dm, plex_to_cgns_sf));
1926472b9844SJames Wright PetscCall(DMSetUseNatural(*dm, PETSC_TRUE));
1927472b9844SJames Wright PetscCall(PetscSFDestroy(&plex_to_cgns_sf));
1928472b9844SJames Wright
1929472b9844SJames Wright PetscCall(PetscLayoutDestroy(&elem_map));
1930472b9844SJames Wright PetscCall(PetscLayoutDestroy(&vtx_map));
19313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
19325f34f2dcSJed Brown }
19335f34f2dcSJed Brown
19345f34f2dcSJed Brown // node_l2g must be freed
DMPlexCreateNodeNumbering(DM dm,PetscInt * num_local_nodes,PetscInt * num_global_nodes,PetscInt * nStart,PetscInt * nEnd,const PetscInt ** node_l2g)1935d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateNodeNumbering(DM dm, PetscInt *num_local_nodes, PetscInt *num_global_nodes, PetscInt *nStart, PetscInt *nEnd, const PetscInt **node_l2g)
1936d71ae5a4SJacob Faibussowitsch {
19375f34f2dcSJed Brown PetscSection local_section;
19385f34f2dcSJed Brown PetscSF point_sf;
19395f34f2dcSJed Brown PetscInt pStart, pEnd, spStart, spEnd, *points, nleaves, ncomp, *nodes;
19405f34f2dcSJed Brown PetscMPIInt comm_size;
19415f34f2dcSJed Brown const PetscInt *ilocal, field = 0;
19425f34f2dcSJed Brown
19435f34f2dcSJed Brown PetscFunctionBegin;
19445f34f2dcSJed Brown *num_local_nodes = -1;
19455f34f2dcSJed Brown *num_global_nodes = -1;
19465f34f2dcSJed Brown *nStart = -1;
19475f34f2dcSJed Brown *nEnd = -1;
19485f34f2dcSJed Brown *node_l2g = NULL;
19495f34f2dcSJed Brown
19505f34f2dcSJed Brown PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &comm_size));
19515f34f2dcSJed Brown PetscCall(DMGetLocalSection(dm, &local_section));
19525f34f2dcSJed Brown PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
19535f34f2dcSJed Brown PetscCall(PetscSectionGetChart(local_section, &spStart, &spEnd));
19545f34f2dcSJed Brown PetscCall(DMGetPointSF(dm, &point_sf));
19555f34f2dcSJed Brown if (comm_size == 1) nleaves = 0;
19565f34f2dcSJed Brown else PetscCall(PetscSFGetGraph(point_sf, NULL, &nleaves, &ilocal, NULL));
19575f34f2dcSJed Brown PetscCall(PetscSectionGetFieldComponents(local_section, field, &ncomp));
19585f34f2dcSJed Brown
19595f34f2dcSJed Brown PetscInt local_node = 0, owned_node = 0, owned_start = 0;
19605f34f2dcSJed Brown for (PetscInt p = spStart, leaf = 0; p < spEnd; p++) {
19615f34f2dcSJed Brown PetscInt dof;
19625f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof));
19635f34f2dcSJed Brown PetscAssert(dof % ncomp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field dof %" PetscInt_FMT " must be divisible by components %" PetscInt_FMT, dof, ncomp);
19645f34f2dcSJed Brown local_node += dof / ncomp;
19655f34f2dcSJed Brown if (leaf < nleaves && p == ilocal[leaf]) { // skip points owned by a different process
19665f34f2dcSJed Brown leaf++;
19675f34f2dcSJed Brown } else {
19685f34f2dcSJed Brown owned_node += dof / ncomp;
19695f34f2dcSJed Brown }
19705f34f2dcSJed Brown }
19715f34f2dcSJed Brown PetscCallMPI(MPI_Exscan(&owned_node, &owned_start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
19725f34f2dcSJed Brown PetscCall(PetscMalloc1(pEnd - pStart, &points));
19735f34f2dcSJed Brown owned_node = 0;
19745f34f2dcSJed Brown for (PetscInt p = spStart, leaf = 0; p < spEnd; p++) {
19755f34f2dcSJed Brown if (leaf < nleaves && p == ilocal[leaf]) { // skip points owned by a different process
19765f34f2dcSJed Brown points[p - pStart] = -1;
19775f34f2dcSJed Brown leaf++;
19785f34f2dcSJed Brown continue;
19795f34f2dcSJed Brown }
19805f34f2dcSJed Brown PetscInt dof, offset;
19815f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof));
19825f34f2dcSJed Brown PetscCall(PetscSectionGetFieldOffset(local_section, p, field, &offset));
19835f34f2dcSJed Brown PetscAssert(offset % ncomp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field offset %" PetscInt_FMT " must be divisible by components %" PetscInt_FMT, offset, ncomp);
19845f34f2dcSJed Brown points[p - pStart] = owned_start + owned_node;
19855f34f2dcSJed Brown owned_node += dof / ncomp;
19865f34f2dcSJed Brown }
19875f34f2dcSJed Brown if (comm_size > 1) {
19885f34f2dcSJed Brown PetscCall(PetscSFBcastBegin(point_sf, MPIU_INT, points, points, MPI_REPLACE));
19895f34f2dcSJed Brown PetscCall(PetscSFBcastEnd(point_sf, MPIU_INT, points, points, MPI_REPLACE));
19905f34f2dcSJed Brown }
19915f34f2dcSJed Brown
19925f34f2dcSJed Brown // Set up global indices for each local node
19935f34f2dcSJed Brown PetscCall(PetscMalloc1(local_node, &nodes));
19945f34f2dcSJed Brown for (PetscInt p = spStart; p < spEnd; p++) {
19955f34f2dcSJed Brown PetscInt dof, offset;
19965f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof));
19975f34f2dcSJed Brown PetscCall(PetscSectionGetFieldOffset(local_section, p, field, &offset));
19985f34f2dcSJed Brown for (PetscInt n = 0; n < dof / ncomp; n++) nodes[offset / ncomp + n] = points[p - pStart] + n;
19995f34f2dcSJed Brown }
20005f34f2dcSJed Brown PetscCall(PetscFree(points));
20015f34f2dcSJed Brown *num_local_nodes = local_node;
20025f34f2dcSJed Brown *nStart = owned_start;
20035f34f2dcSJed Brown *nEnd = owned_start + owned_node;
2004462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&owned_node, num_global_nodes, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm)));
20055f34f2dcSJed Brown *node_l2g = nodes;
20063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
20075f34f2dcSJed Brown }
20085f34f2dcSJed Brown
DMView_PlexCGNS(DM dm,PetscViewer viewer)2009d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_PlexCGNS(DM dm, PetscViewer viewer)
2010d71ae5a4SJacob Faibussowitsch {
2011d0c2e842SJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)dm);
20125f34f2dcSJed Brown PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data;
201344698e90SJames Wright PetscInt fvGhostStart;
20145f34f2dcSJed Brown PetscInt topo_dim, coord_dim, num_global_elems;
2015*3458b7b5SJames Wright PetscInt cStart, cEnd, num_local_nodes, num_global_nodes, nStart, nEnd, fStart, fEnd;
20165f34f2dcSJed Brown const PetscInt *node_l2g;
20175f34f2dcSJed Brown Vec coord;
2018b85bf5edSJed Brown DM colloc_dm, cdm;
20195f34f2dcSJed Brown PetscMPIInt size;
20205f34f2dcSJed Brown const char *dm_name;
20215f34f2dcSJed Brown int base, zone;
2022*3458b7b5SJames Wright cgsize_t isize[3], elem_offset = 0;
20235f34f2dcSJed Brown
20245f34f2dcSJed Brown PetscFunctionBegin;
202525760affSJed Brown if (!cgv->file_num) {
202625760affSJed Brown PetscInt time_step;
202725760affSJed Brown PetscCall(DMGetOutputSequenceNumber(dm, &time_step, NULL));
202825760affSJed Brown PetscCall(PetscViewerCGNSFileOpen_Internal(viewer, time_step));
202925760affSJed Brown }
2030d0c2e842SJames Wright PetscCallMPI(MPI_Comm_size(comm, &size));
20315f34f2dcSJed Brown PetscCall(DMGetDimension(dm, &topo_dim));
20325f34f2dcSJed Brown PetscCall(DMGetCoordinateDim(dm, &coord_dim));
20335f34f2dcSJed Brown PetscCall(PetscObjectGetName((PetscObject)dm, &dm_name));
20344c155f28SJames Wright PetscCallCGNSWrite(cg_base_write(cgv->file_num, dm_name, topo_dim, coord_dim, &base), dm, viewer);
20355f34f2dcSJed Brown PetscCallCGNS(cg_goto(cgv->file_num, base, NULL));
20364c155f28SJames Wright PetscCallCGNSWrite(cg_dataclass_write(CGNS_ENUMV(NormalizedByDimensional)), dm, viewer);
20375f34f2dcSJed Brown
2038b85bf5edSJed Brown {
2039b85bf5edSJed Brown PetscFE fe, fe_coord;
20409bb8f83bSJed Brown PetscClassId ds_id;
2041b85bf5edSJed Brown PetscDualSpace dual_space, dual_space_coord;
20422d1fc720SJed Brown PetscInt num_fields, field_order = -1, field_order_coord;
2043b85bf5edSJed Brown PetscBool is_simplex;
20445b8b2c14SJed Brown PetscCall(DMGetNumFields(dm, &num_fields));
20459bb8f83bSJed Brown if (num_fields > 0) {
20469bb8f83bSJed Brown PetscCall(DMGetField(dm, 0, NULL, (PetscObject *)&fe));
20479bb8f83bSJed Brown PetscCall(PetscObjectGetClassId((PetscObject)fe, &ds_id));
20482d1fc720SJed Brown if (ds_id != PETSCFE_CLASSID) {
20492d1fc720SJed Brown fe = NULL;
20502d1fc720SJed Brown if (ds_id == PETSCFV_CLASSID) field_order = -1; // use whatever is present for coords; field will be CellCenter
20512d1fc720SJed Brown else field_order = 1; // assume vertex-based linear elements
20522d1fc720SJed Brown }
20539bb8f83bSJed Brown } else fe = NULL;
2054b85bf5edSJed Brown if (fe) {
2055b85bf5edSJed Brown PetscCall(PetscFEGetDualSpace(fe, &dual_space));
2056b85bf5edSJed Brown PetscCall(PetscDualSpaceGetOrder(dual_space, &field_order));
20572d1fc720SJed Brown }
20585f34f2dcSJed Brown PetscCall(DMGetCoordinateDM(dm, &cdm));
2059b85bf5edSJed Brown PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe_coord));
20609bb8f83bSJed Brown {
20619bb8f83bSJed Brown PetscClassId id;
20629bb8f83bSJed Brown PetscCall(PetscObjectGetClassId((PetscObject)fe_coord, &id));
20639bb8f83bSJed Brown if (id != PETSCFE_CLASSID) fe_coord = NULL;
20649bb8f83bSJed Brown }
2065b85bf5edSJed Brown if (fe_coord) {
2066b85bf5edSJed Brown PetscCall(PetscFEGetDualSpace(fe_coord, &dual_space_coord));
2067b85bf5edSJed Brown PetscCall(PetscDualSpaceGetOrder(dual_space_coord, &field_order_coord));
2068b85bf5edSJed Brown } else field_order_coord = 1;
20692d1fc720SJed Brown if (field_order > 0 && field_order != field_order_coord) {
2070b85bf5edSJed Brown PetscInt quadrature_order = field_order;
2071b85bf5edSJed Brown PetscCall(DMClone(dm, &colloc_dm));
20727d4eb7abSJed Brown { // Inform the new colloc_dm that it is a coordinate DM so isoperiodic affine corrections can be applied
20731fca310dSJames Wright const PetscSF *face_sfs;
20741fca310dSJames Wright PetscInt num_face_sfs;
20751fca310dSJames Wright PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs));
20761fca310dSJames Wright PetscCall(DMPlexSetIsoperiodicFaceSF(colloc_dm, num_face_sfs, (PetscSF *)face_sfs));
20771fca310dSJames Wright if (face_sfs) colloc_dm->periodic.setup = DMPeriodicCoordinateSetUp_Internal;
20787d4eb7abSJed Brown }
2079b85bf5edSJed Brown PetscCall(DMPlexIsSimplex(dm, &is_simplex));
2080d0c2e842SJames Wright PetscCall(PetscFECreateLagrange(comm, topo_dim, coord_dim, is_simplex, field_order, quadrature_order, &fe));
20814c712d99Sksagiyam PetscCall(DMSetCoordinateDisc(colloc_dm, fe, PETSC_FALSE, PETSC_TRUE));
2082b85bf5edSJed Brown PetscCall(PetscFEDestroy(&fe));
2083b85bf5edSJed Brown } else {
2084b85bf5edSJed Brown PetscCall(PetscObjectReference((PetscObject)dm));
2085b85bf5edSJed Brown colloc_dm = dm;
2086b85bf5edSJed Brown }
2087b85bf5edSJed Brown }
2088b85bf5edSJed Brown PetscCall(DMGetCoordinateDM(colloc_dm, &cdm));
20895f34f2dcSJed Brown PetscCall(DMPlexCreateNodeNumbering(cdm, &num_local_nodes, &num_global_nodes, &nStart, &nEnd, &node_l2g));
2090b85bf5edSJed Brown PetscCall(DMGetCoordinatesLocal(colloc_dm, &coord));
20915f34f2dcSJed Brown PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
2092*3458b7b5SJames Wright PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
209344698e90SJames Wright PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &fvGhostStart, NULL));
209444698e90SJames Wright if (fvGhostStart >= 0) cEnd = fvGhostStart;
20955f34f2dcSJed Brown num_global_elems = cEnd - cStart;
2096d0c2e842SJames Wright PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &num_global_elems, 1, MPIU_INT, MPI_SUM, comm));
20975f34f2dcSJed Brown isize[0] = num_global_nodes;
20985f34f2dcSJed Brown isize[1] = num_global_elems;
20995f34f2dcSJed Brown isize[2] = 0;
21004c155f28SJames Wright PetscCallCGNSWrite(cg_zone_write(cgv->file_num, base, "Zone", isize, CGNS_ENUMV(Unstructured), &zone), dm, viewer);
21015f34f2dcSJed Brown
2102*3458b7b5SJames Wright cgsize_t e_owned, e_global, e_start;
21035f34f2dcSJed Brown {
21045f34f2dcSJed Brown const PetscScalar *X;
21055f34f2dcSJed Brown PetscScalar *x;
21065f34f2dcSJed Brown int coord_ids[3];
21075f34f2dcSJed Brown
21085f34f2dcSJed Brown PetscCall(VecGetArrayRead(coord, &X));
21095f34f2dcSJed Brown for (PetscInt d = 0; d < coord_dim; d++) {
21105f34f2dcSJed Brown const double exponents[] = {0, 1, 0, 0, 0};
21115f34f2dcSJed Brown char coord_name[64];
21125f34f2dcSJed Brown PetscCall(PetscSNPrintf(coord_name, sizeof coord_name, "Coordinate%c", 'X' + (int)d));
21134c155f28SJames Wright PetscCallCGNSWrite(cgp_coord_write(cgv->file_num, base, zone, CGNS_ENUMV(RealDouble), coord_name, &coord_ids[d]), dm, viewer);
21145f34f2dcSJed Brown PetscCallCGNS(cg_goto(cgv->file_num, base, "Zone_t", zone, "GridCoordinates", 0, coord_name, 0, NULL));
21154c155f28SJames Wright PetscCallCGNSWrite(cg_exponents_write(CGNS_ENUMV(RealDouble), exponents), dm, viewer);
21165f34f2dcSJed Brown }
21175f34f2dcSJed Brown
21185f34f2dcSJed Brown int section;
2119*3458b7b5SJames Wright cgsize_t *conn = NULL;
21205f34f2dcSJed Brown const int *perm;
2121e853fb4cSJames Wright CGNS_ENUMT(ElementType_t) element_type = CGNS_ENUMV(ElementTypeNull);
21225f34f2dcSJed Brown {
21235f34f2dcSJed Brown PetscCall(PetscMalloc1(nEnd - nStart, &x));
21245f34f2dcSJed Brown for (PetscInt d = 0; d < coord_dim; d++) {
21255f34f2dcSJed Brown for (PetscInt n = 0; n < num_local_nodes; n++) {
21265f34f2dcSJed Brown PetscInt gn = node_l2g[n];
21275f34f2dcSJed Brown if (gn < nStart || nEnd <= gn) continue;
21285f34f2dcSJed Brown x[gn - nStart] = X[n * coord_dim + d];
21295f34f2dcSJed Brown }
21305f34f2dcSJed Brown // CGNS nodes use 1-based indexing
21315f34f2dcSJed Brown cgsize_t start = nStart + 1, end = nEnd;
21324c155f28SJames Wright PetscCallCGNSWriteData(cgp_coord_write_data(cgv->file_num, base, zone, coord_ids[d], &start, &end, x), dm, viewer);
21335f34f2dcSJed Brown }
21345f34f2dcSJed Brown PetscCall(PetscFree(x));
21355f34f2dcSJed Brown PetscCall(VecRestoreArrayRead(coord, &X));
21365f34f2dcSJed Brown }
21375f34f2dcSJed Brown
213859191b1eSJames Wright e_owned = cEnd - cStart;
213944698e90SJames Wright if (e_owned > 0) {
214044698e90SJames Wright DMPolytopeType cell_type;
214144698e90SJames Wright
214244698e90SJames Wright PetscCall(DMPlexGetCellType(dm, cStart, &cell_type));
21435f34f2dcSJed Brown for (PetscInt i = cStart, c = 0; i < cEnd; i++) {
21445f34f2dcSJed Brown PetscInt closure_dof, *closure_indices, elem_size;
214544698e90SJames Wright
21465f34f2dcSJed Brown PetscCall(DMPlexGetClosureIndices(cdm, cdm->localSection, cdm->localSection, i, PETSC_FALSE, &closure_dof, &closure_indices, NULL, NULL));
21475f34f2dcSJed Brown elem_size = closure_dof / coord_dim;
214844698e90SJames Wright if (!conn) PetscCall(PetscMalloc1(e_owned * elem_size, &conn));
21495f34f2dcSJed Brown PetscCall(DMPlexCGNSGetPermutation_Internal(cell_type, closure_dof / coord_dim, &element_type, &perm));
2150ad540459SPierre Jolivet for (PetscInt j = 0; j < elem_size; j++) conn[c++] = node_l2g[closure_indices[perm[j] * coord_dim] / coord_dim] + 1;
21515f34f2dcSJed Brown PetscCall(DMPlexRestoreClosureIndices(cdm, cdm->localSection, cdm->localSection, i, PETSC_FALSE, &closure_dof, &closure_indices, NULL, NULL));
21525f34f2dcSJed Brown }
215344698e90SJames Wright }
215444698e90SJames Wright
215559191b1eSJames Wright { // Get global element_type (for ranks that do not have owned elements)
215659191b1eSJames Wright PetscInt local_element_type, global_element_type;
215759191b1eSJames Wright
21588fd9df95SJames Wright local_element_type = e_owned > 0 ? (PetscInt)element_type : -1;
2159d0c2e842SJames Wright PetscCallMPI(MPIU_Allreduce(&local_element_type, &global_element_type, 1, MPIU_INT, MPI_MAX, comm));
2160*3458b7b5SJames Wright if (local_element_type != -1)
2161*3458b7b5SJames Wright PetscCheck(local_element_type == global_element_type, PETSC_COMM_SELF, PETSC_ERR_SUP, "Ranks with different element types not supported. Local element type is %s, but global is %s", cg_ElementTypeName(local_element_type), cg_ElementTypeName(global_element_type));
2162ca328833SJames Wright element_type = (CGNS_ENUMT(ElementType_t))global_element_type;
216359191b1eSJames Wright }
2164d0c2e842SJames Wright PetscCallMPI(MPIU_Allreduce(&e_owned, &e_global, 1, MPIU_CGSIZE, MPI_SUM, comm));
21651fb9530eSJeongu Kim PetscCheck(e_global == num_global_elems, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of elements %" PRIdCGSIZE " vs %" PetscInt_FMT, e_global, num_global_elems);
21665f34f2dcSJed Brown e_start = 0;
2167d0c2e842SJames Wright PetscCallMPI(MPI_Exscan(&e_owned, &e_start, 1, MPIU_CGSIZE, MPI_SUM, comm));
2168*3458b7b5SJames Wright e_start += elem_offset;
21694c155f28SJames Wright PetscCallCGNSWrite(cgp_section_write(cgv->file_num, base, zone, "Elem", element_type, 1, e_global, 0, §ion), dm, viewer);
21704c155f28SJames Wright PetscCallCGNSWriteData(cgp_elements_write_data(cgv->file_num, base, zone, section, e_start + 1, e_start + e_owned, conn), dm, viewer);
2171*3458b7b5SJames Wright elem_offset = e_global;
21725f34f2dcSJed Brown PetscCall(PetscFree(conn));
21735f34f2dcSJed Brown
21745f34f2dcSJed Brown cgv->base = base;
21755f34f2dcSJed Brown cgv->zone = zone;
21765f34f2dcSJed Brown cgv->node_l2g = node_l2g;
21775f34f2dcSJed Brown cgv->num_local_nodes = num_local_nodes;
21785f34f2dcSJed Brown cgv->nStart = nStart;
21795f34f2dcSJed Brown cgv->nEnd = nEnd;
21809bb8f83bSJed Brown cgv->eStart = e_start;
21819bb8f83bSJed Brown cgv->eEnd = e_start + e_owned;
21825f34f2dcSJed Brown if (1) {
21835f34f2dcSJed Brown PetscMPIInt rank;
21845f34f2dcSJed Brown int *efield;
21855f34f2dcSJed Brown int sol, field;
21865f34f2dcSJed Brown DMLabel label;
2187d0c2e842SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank));
21885f34f2dcSJed Brown PetscCall(PetscMalloc1(e_owned, &efield));
21895f34f2dcSJed Brown for (PetscInt i = 0; i < e_owned; i++) efield[i] = rank;
21904c155f28SJames Wright PetscCallCGNSWrite(cg_sol_write(cgv->file_num, base, zone, "CellInfo", CGNS_ENUMV(CellCenter), &sol), dm, viewer);
21914c155f28SJames Wright PetscCallCGNSWrite(cgp_field_write(cgv->file_num, base, zone, sol, CGNS_ENUMV(Integer), "Rank", &field), dm, viewer);
21925f34f2dcSJed Brown cgsize_t start = e_start + 1, end = e_start + e_owned;
21934c155f28SJames Wright PetscCallCGNSWriteData(cgp_field_write_data(cgv->file_num, base, zone, sol, field, &start, &end, efield), dm, viewer);
21945f34f2dcSJed Brown PetscCall(DMGetLabel(dm, "Cell Sets", &label));
21955f34f2dcSJed Brown if (label) {
21965f34f2dcSJed Brown for (PetscInt c = cStart; c < cEnd; c++) {
21975f34f2dcSJed Brown PetscInt value;
21985f34f2dcSJed Brown PetscCall(DMLabelGetValue(label, c, &value));
21995f34f2dcSJed Brown efield[c - cStart] = value;
22005f34f2dcSJed Brown }
22014c155f28SJames Wright PetscCallCGNSWrite(cgp_field_write(cgv->file_num, base, zone, sol, CGNS_ENUMV(Integer), "CellSet", &field), dm, viewer);
22024c155f28SJames Wright PetscCallCGNSWriteData(cgp_field_write_data(cgv->file_num, base, zone, sol, field, &start, &end, efield), dm, viewer);
22035f34f2dcSJed Brown }
22045f34f2dcSJed Brown PetscCall(PetscFree(efield));
22055f34f2dcSJed Brown }
22065f34f2dcSJed Brown }
2207*3458b7b5SJames Wright
2208*3458b7b5SJames Wright DMLabel fsLabel;
2209*3458b7b5SJames Wright PetscInt num_fs_global;
2210*3458b7b5SJames Wright IS fsValuesGlobalIS;
2211*3458b7b5SJames Wright PetscCall(DMGetLabel(dm, "Face Sets", &fsLabel));
2212*3458b7b5SJames Wright PetscCall(DMLabelGetValueISGlobal(comm, fsLabel, PETSC_TRUE, &fsValuesGlobalIS));
2213*3458b7b5SJames Wright PetscCall(ISGetSize(fsValuesGlobalIS, &num_fs_global));
2214*3458b7b5SJames Wright
2215*3458b7b5SJames Wright if (num_fs_global > 0) {
2216*3458b7b5SJames Wright CGNS_ENUMT(ElementType_t) element_type = CGNS_ENUMV(ElementTypeNull);
2217*3458b7b5SJames Wright const PetscInt *fsValuesLocal;
2218*3458b7b5SJames Wright IS stratumIS, fsFacesAll;
2219*3458b7b5SJames Wright int section;
2220*3458b7b5SJames Wright const int *perm;
2221*3458b7b5SJames Wright cgsize_t f_owned = 0, f_global, f_start;
2222*3458b7b5SJames Wright cgsize_t *parents, *conn = NULL;
2223*3458b7b5SJames Wright PetscInt fStart, fEnd;
2224*3458b7b5SJames Wright
2225*3458b7b5SJames Wright PetscInt num_fs_local;
2226*3458b7b5SJames Wright IS fsValuesLocalIS;
2227*3458b7b5SJames Wright
2228*3458b7b5SJames Wright if (fsLabel) {
2229*3458b7b5SJames Wright PetscCall(DMLabelGetNonEmptyStratumValuesIS(fsLabel, &fsValuesLocalIS));
2230*3458b7b5SJames Wright PetscCall(ISGetSize(fsValuesLocalIS, &num_fs_local));
2231*3458b7b5SJames Wright PetscCall(ISGetIndices(fsValuesLocalIS, &fsValuesLocal));
2232*3458b7b5SJames Wright } else num_fs_local = 0;
2233*3458b7b5SJames Wright
2234*3458b7b5SJames Wright PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2235*3458b7b5SJames Wright { // Get single IS without duplicates of the local face IDs in the FaceSets
2236*3458b7b5SJames Wright IS *fsPoints = NULL;
2237*3458b7b5SJames Wright
2238*3458b7b5SJames Wright PetscCall(PetscMalloc1(num_fs_local, &fsPoints));
2239*3458b7b5SJames Wright for (PetscInt fs = 0; fs < num_fs_local; ++fs) PetscCall(DMLabelGetStratumIS(fsLabel, fsValuesLocal[fs], &fsPoints[fs]));
2240*3458b7b5SJames Wright PetscCall(ISConcatenate(PETSC_COMM_SELF, num_fs_local, fsPoints, &fsFacesAll));
2241*3458b7b5SJames Wright PetscCall(ISSortRemoveDups(fsFacesAll));
2242*3458b7b5SJames Wright PetscCall(ISGeneralFilter(fsFacesAll, fStart, fEnd)); // Remove non-face mesh points from the IS
2243*3458b7b5SJames Wright {
2244*3458b7b5SJames Wright PetscInt f_owned_int;
2245*3458b7b5SJames Wright PetscCall(ISGetSize(fsFacesAll, &f_owned_int));
2246*3458b7b5SJames Wright f_owned = f_owned_int;
2247*3458b7b5SJames Wright }
2248*3458b7b5SJames Wright for (PetscInt fs = 0; fs < num_fs_local; ++fs) PetscCall(ISDestroy(&fsPoints[fs]));
2249*3458b7b5SJames Wright PetscCall(PetscFree(fsPoints));
2250*3458b7b5SJames Wright }
2251*3458b7b5SJames Wright PetscCall(ISRestoreIndices(fsValuesLocalIS, &fsValuesLocal));
2252*3458b7b5SJames Wright PetscCall(ISDestroy(&fsValuesLocalIS));
2253*3458b7b5SJames Wright
2254*3458b7b5SJames Wright {
2255*3458b7b5SJames Wright const PetscInt *faces;
2256*3458b7b5SJames Wright DMPolytopeType cell_type, cell_type_f;
2257*3458b7b5SJames Wright PetscInt closure_dof = -1, closure_dof_f;
2258*3458b7b5SJames Wright
2259*3458b7b5SJames Wright PetscCall(ISGetIndices(fsFacesAll, &faces));
2260*3458b7b5SJames Wright if (f_owned) PetscCall(DMPlexGetCellType(dm, faces[0], &cell_type));
2261*3458b7b5SJames Wright PetscCall(PetscCalloc1(f_owned * 2, &parents));
2262*3458b7b5SJames Wright for (PetscInt f = 0, c = 0; f < f_owned; f++) {
2263*3458b7b5SJames Wright PetscInt *closure_indices, elem_size;
2264*3458b7b5SJames Wright const PetscInt face = faces[f];
2265*3458b7b5SJames Wright
2266*3458b7b5SJames Wright PetscCall(DMPlexGetCellType(dm, face, &cell_type_f));
2267*3458b7b5SJames Wright PetscCheck(cell_type_f == cell_type, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Only mono-topology face sets are supported currently. Face %" PetscInt_FMT " is %s, which is different than the previous type %s", face, DMPolytopeTypes[cell_type_f], DMPolytopeTypes[cell_type]);
2268*3458b7b5SJames Wright
2269*3458b7b5SJames Wright // Get connectivity of the face
2270*3458b7b5SJames Wright PetscCall(DMPlexGetClosureIndices(cdm, cdm->localSection, cdm->localSection, face, PETSC_FALSE, &closure_dof_f, &closure_indices, NULL, NULL));
2271*3458b7b5SJames Wright elem_size = closure_dof_f / coord_dim;
2272*3458b7b5SJames Wright if (!conn) {
2273*3458b7b5SJames Wright PetscCall(PetscMalloc1(f_owned * elem_size, &conn));
2274*3458b7b5SJames Wright closure_dof = closure_dof_f;
2275*3458b7b5SJames Wright }
2276*3458b7b5SJames Wright PetscCheck(closure_dof_f == closure_dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Closure of face %" PetscInt_FMT " has %" PetscInt_FMT " dofs instead of the previously written %" PetscInt_FMT " dofs. Only mono-topology face sets are supported currently", face, closure_dof_f, closure_dof);
2277*3458b7b5SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(cell_type, elem_size, &element_type, &perm));
2278*3458b7b5SJames Wright for (PetscInt j = 0; j < elem_size; j++) conn[c++] = node_l2g[closure_indices[perm[j] * coord_dim] / coord_dim] + 1;
2279*3458b7b5SJames Wright PetscCall(DMPlexRestoreClosureIndices(cdm, cdm->localSection, cdm->localSection, face, PETSC_FALSE, &closure_dof_f, &closure_indices, NULL, NULL));
2280*3458b7b5SJames Wright }
2281*3458b7b5SJames Wright PetscCall(ISRestoreIndices(fsFacesAll, &faces));
2282*3458b7b5SJames Wright }
2283*3458b7b5SJames Wright
2284*3458b7b5SJames Wright { // Write connectivity for face sets
2285*3458b7b5SJames Wright { // Get global element type
2286*3458b7b5SJames Wright PetscInt local_element_type, global_element_type;
2287*3458b7b5SJames Wright
2288*3458b7b5SJames Wright local_element_type = f_owned > 0 ? (PetscInt)element_type : -1;
2289*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(&local_element_type, &global_element_type, 1, MPIU_INT, MPI_MAX, comm));
2290*3458b7b5SJames Wright if (local_element_type != -1)
2291*3458b7b5SJames Wright PetscCheck(local_element_type == global_element_type, PETSC_COMM_SELF, PETSC_ERR_SUP, "Ranks with different element types not supported. Local element type is %s, but global is %s", cg_ElementTypeName(local_element_type), cg_ElementTypeName(global_element_type));
2292*3458b7b5SJames Wright element_type = (CGNS_ENUMT(ElementType_t))global_element_type;
2293*3458b7b5SJames Wright }
2294*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(&f_owned, &f_global, 1, MPIU_CGSIZE, MPI_SUM, comm));
2295*3458b7b5SJames Wright f_start = 0;
2296*3458b7b5SJames Wright PetscCallMPI(MPI_Exscan(&f_owned, &f_start, 1, MPIU_CGSIZE, MPI_SUM, comm));
2297*3458b7b5SJames Wright f_start += elem_offset;
2298*3458b7b5SJames Wright PetscCallCGNSWrite(cgp_section_write(cgv->file_num, base, zone, "Faces", element_type, elem_offset + 1, elem_offset + f_global, 0, §ion), dm, viewer);
2299*3458b7b5SJames Wright PetscCallCGNSWriteData(cgp_elements_write_data(cgv->file_num, base, zone, section, f_start + 1, f_start + f_owned, conn), dm, viewer);
2300*3458b7b5SJames Wright
2301*3458b7b5SJames Wright PetscCall(PetscFree(conn));
2302*3458b7b5SJames Wright PetscCall(PetscFree(parents));
2303*3458b7b5SJames Wright }
2304*3458b7b5SJames Wright
2305*3458b7b5SJames Wright const PetscInt *fsValuesGlobal = NULL;
2306*3458b7b5SJames Wright PetscCall(ISGetIndices(fsValuesGlobalIS, &fsValuesGlobal));
2307*3458b7b5SJames Wright for (PetscInt fs = 0; fs < num_fs_global; ++fs) {
2308*3458b7b5SJames Wright int BC;
2309*3458b7b5SJames Wright const PetscInt fsID = fsValuesGlobal[fs];
2310*3458b7b5SJames Wright PetscInt *fs_pnts = NULL;
2311*3458b7b5SJames Wright char bc_name[33];
2312*3458b7b5SJames Wright cgsize_t fs_start, fs_owned, fs_global;
2313*3458b7b5SJames Wright cgsize_t *fs_pnts_cg;
2314*3458b7b5SJames Wright
2315*3458b7b5SJames Wright PetscCall(DMLabelGetStratumIS(fsLabel, fsID, &stratumIS));
2316*3458b7b5SJames Wright if (stratumIS) { // Get list of only face points
2317*3458b7b5SJames Wright PetscSegBuffer fs_pntsSB;
2318*3458b7b5SJames Wright PetscCount fs_owned_count;
2319*3458b7b5SJames Wright PetscInt nstratumPnts;
2320*3458b7b5SJames Wright const PetscInt *stratumPnts;
2321*3458b7b5SJames Wright
2322*3458b7b5SJames Wright PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 16, &fs_pntsSB));
2323*3458b7b5SJames Wright PetscCall(ISGetIndices(stratumIS, &stratumPnts));
2324*3458b7b5SJames Wright PetscCall(ISGetSize(stratumIS, &nstratumPnts));
2325*3458b7b5SJames Wright for (PetscInt i = 0; i < nstratumPnts; i++) {
2326*3458b7b5SJames Wright PetscInt *fs_pnts_buffer, stratumPnt = stratumPnts[i];
2327*3458b7b5SJames Wright if (stratumPnt < fStart || stratumPnt >= fEnd) continue; // Skip non-face points
2328*3458b7b5SJames Wright PetscCall(PetscSegBufferGetInts(fs_pntsSB, 1, &fs_pnts_buffer));
2329*3458b7b5SJames Wright *fs_pnts_buffer = stratumPnt;
2330*3458b7b5SJames Wright }
2331*3458b7b5SJames Wright PetscCall(PetscSegBufferGetSize(fs_pntsSB, &fs_owned_count));
2332*3458b7b5SJames Wright fs_owned = fs_owned_count;
2333*3458b7b5SJames Wright PetscCall(PetscSegBufferExtractAlloc(fs_pntsSB, &fs_pnts));
2334*3458b7b5SJames Wright
2335*3458b7b5SJames Wright PetscCall(PetscSegBufferDestroy(&fs_pntsSB));
2336*3458b7b5SJames Wright PetscCall(ISRestoreIndices(stratumIS, &stratumPnts));
2337*3458b7b5SJames Wright PetscCall(ISDestroy(&stratumIS));
2338*3458b7b5SJames Wright } else fs_owned = 0;
2339*3458b7b5SJames Wright
2340*3458b7b5SJames Wright PetscCallMPI(MPIU_Allreduce(&fs_owned, &fs_global, 1, MPIU_CGSIZE, MPI_SUM, comm));
2341*3458b7b5SJames Wright fs_start = 0;
2342*3458b7b5SJames Wright PetscCallMPI(MPI_Exscan(&fs_owned, &fs_start, 1, MPIU_CGSIZE, MPI_SUM, comm));
2343*3458b7b5SJames Wright PetscCheck(fs_start + fs_owned <= fs_global, PETSC_COMM_SELF, PETSC_ERR_PLIB, "End range of point set (%" PRIdCGSIZE ") greater than global point set size (%" PRIdCGSIZE ")", fs_start + fs_owned, fs_global);
2344*3458b7b5SJames Wright
2345*3458b7b5SJames Wright PetscCall(PetscSNPrintf(bc_name, sizeof bc_name, "FaceSet%" PetscInt_FMT, fsID));
2346*3458b7b5SJames Wright PetscCallCGNSWrite(cg_boco_write(cgv->file_num, base, zone, bc_name, CGNS_ENUMV(BCTypeNull), CGNS_ENUMV(PointList), fs_global, NULL, &BC), dm, viewer);
2347*3458b7b5SJames Wright
2348*3458b7b5SJames Wright PetscCall(PetscMalloc1(fs_owned, &fs_pnts_cg));
2349*3458b7b5SJames Wright for (PetscInt i = 0; i < fs_owned; i++) {
2350*3458b7b5SJames Wright PetscInt is_idx;
2351*3458b7b5SJames Wright
2352*3458b7b5SJames Wright PetscCall(ISLocate(fsFacesAll, fs_pnts[i], &is_idx));
2353*3458b7b5SJames Wright PetscCheck(is_idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %" PetscInt_FMT " in list of all local face points", fs_pnts[i]);
2354*3458b7b5SJames Wright fs_pnts_cg[i] = is_idx + f_start + 1;
2355*3458b7b5SJames Wright }
2356*3458b7b5SJames Wright
2357*3458b7b5SJames Wright const char *labels[] = {"Zone_t", "ZoneBC_t", "BC_t", "PointList"};
2358*3458b7b5SJames Wright PetscCallCGNSWrite(cg_golist(cgv->file_num, base, 4, (char **)labels, (int[]){zone, 1, BC, 0}), dm, 0);
2359*3458b7b5SJames Wright PetscCallCGNSWriteData(cgp_ptlist_write_data(cgv->file_num, fs_start + 1, fs_start + fs_owned, fs_pnts_cg), dm, viewer);
2360*3458b7b5SJames Wright
2361*3458b7b5SJames Wright CGNS_ENUMT(GridLocation_t) grid_loc = CGNS_ENUMV(GridLocationNull);
2362*3458b7b5SJames Wright if (topo_dim == 3) grid_loc = CGNS_ENUMV(FaceCenter);
2363*3458b7b5SJames Wright else if (topo_dim == 2) grid_loc = CGNS_ENUMV(EdgeCenter);
2364*3458b7b5SJames Wright else if (topo_dim == 1) grid_loc = CGNS_ENUMV(Vertex);
2365*3458b7b5SJames Wright PetscCallCGNSWriteData(cg_boco_gridlocation_write(cgv->file_num, base, zone, BC, grid_loc), dm, viewer);
2366*3458b7b5SJames Wright
2367*3458b7b5SJames Wright PetscCall(PetscFree(fs_pnts_cg));
2368*3458b7b5SJames Wright PetscCall(PetscFree(fs_pnts));
2369*3458b7b5SJames Wright }
2370*3458b7b5SJames Wright PetscCall(ISDestroy(&fsFacesAll));
2371*3458b7b5SJames Wright PetscCall(ISRestoreIndices(fsValuesGlobalIS, &fsValuesGlobal));
2372*3458b7b5SJames Wright elem_offset += f_global;
2373*3458b7b5SJames Wright }
2374*3458b7b5SJames Wright PetscCall(ISDestroy(&fsValuesGlobalIS));
2375*3458b7b5SJames Wright
2376b85bf5edSJed Brown PetscCall(DMDestroy(&colloc_dm));
23773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
23785f34f2dcSJed Brown }
23795f34f2dcSJed Brown
VecView_Plex_Local_CGNS(Vec V,PetscViewer viewer)2380d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local_CGNS(Vec V, PetscViewer viewer)
2381d71ae5a4SJacob Faibussowitsch {
23825f34f2dcSJed Brown PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data;
23835f34f2dcSJed Brown DM dm;
23845f34f2dcSJed Brown PetscSection section;
238544698e90SJames Wright PetscInt time_step, num_fields, pStart, pEnd, fvGhostStart;
23865f34f2dcSJed Brown PetscReal time, *time_slot;
23879812b6beSJed Brown size_t *step_slot;
23885f34f2dcSJed Brown const PetscScalar *v;
23895f34f2dcSJed Brown char solution_name[PETSC_MAX_PATH_LEN];
23905f34f2dcSJed Brown int sol;
23915f34f2dcSJed Brown
23925f34f2dcSJed Brown PetscFunctionBegin;
23935f34f2dcSJed Brown PetscCall(VecGetDM(V, &dm));
2394ec2db9e4SJames Wright PetscCall(DMGetLocalSection(dm, §ion));
2395ec2db9e4SJames Wright PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
239644698e90SJames Wright PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &fvGhostStart, NULL));
239744698e90SJames Wright if (fvGhostStart >= 0) pEnd = fvGhostStart;
2398ec2db9e4SJames Wright
23995f34f2dcSJed Brown if (!cgv->node_l2g) PetscCall(DMView(dm, viewer));
2400ec2db9e4SJames Wright if (!cgv->grid_loc) { // Determine if writing to cell-centers or to nodes
2401ec2db9e4SJames Wright PetscInt cStart, cEnd;
2402ec2db9e4SJames Wright PetscInt local_grid_loc, global_grid_loc;
2403ec2db9e4SJames Wright
2404ec2db9e4SJames Wright PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
240544698e90SJames Wright if (fvGhostStart >= 0) cEnd = fvGhostStart;
2406ec2db9e4SJames Wright if (cgv->num_local_nodes == 0) local_grid_loc = -1;
2407ec2db9e4SJames Wright else if (cStart == pStart && cEnd == pEnd) local_grid_loc = CGNS_ENUMV(CellCenter);
2408ec2db9e4SJames Wright else local_grid_loc = CGNS_ENUMV(Vertex);
2409ec2db9e4SJames Wright
2410462c564dSBarry Smith PetscCallMPI(MPIU_Allreduce(&local_grid_loc, &global_grid_loc, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)viewer)));
2411ec2db9e4SJames Wright if (local_grid_loc != -1)
2412ec2db9e4SJames Wright PetscCheck(local_grid_loc == global_grid_loc, PETSC_COMM_SELF, PETSC_ERR_SUP, "Ranks with different grid locations not supported. Local has %" PetscInt_FMT ", allreduce returned %" PetscInt_FMT, local_grid_loc, global_grid_loc);
2413ec2db9e4SJames Wright PetscCheck((global_grid_loc == CGNS_ENUMV(CellCenter)) || (global_grid_loc == CGNS_ENUMV(Vertex)), PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Grid location should only be CellCenter (%d) or Vertex(%d), but have %" PetscInt_FMT, CGNS_ENUMV(CellCenter), CGNS_ENUMV(Vertex), global_grid_loc);
2414ca328833SJames Wright cgv->grid_loc = (CGNS_ENUMT(GridLocation_t))global_grid_loc;
2415ec2db9e4SJames Wright }
2416ec2db9e4SJames Wright if (!cgv->nodal_field) {
2417ec2db9e4SJames Wright switch (cgv->grid_loc) {
2418ec2db9e4SJames Wright case CGNS_ENUMV(Vertex): {
2419ec2db9e4SJames Wright PetscCall(PetscMalloc1(cgv->nEnd - cgv->nStart, &cgv->nodal_field));
2420ec2db9e4SJames Wright } break;
2421ec2db9e4SJames Wright case CGNS_ENUMV(CellCenter): {
2422ec2db9e4SJames Wright PetscCall(PetscMalloc1(cgv->eEnd - cgv->eStart, &cgv->nodal_field));
2423ec2db9e4SJames Wright } break;
2424ec2db9e4SJames Wright default:
2425ec2db9e4SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only write for Vertex and CellCenter grid locations");
2426ec2db9e4SJames Wright }
2427ec2db9e4SJames Wright }
24285f34f2dcSJed Brown if (!cgv->output_times) PetscCall(PetscSegBufferCreate(sizeof(PetscReal), 20, &cgv->output_times));
24299812b6beSJed Brown if (!cgv->output_steps) PetscCall(PetscSegBufferCreate(sizeof(size_t), 20, &cgv->output_steps));
24305f34f2dcSJed Brown
24315f34f2dcSJed Brown PetscCall(DMGetOutputSequenceNumber(dm, &time_step, &time));
24329371c9d4SSatish Balay if (time_step < 0) {
24339371c9d4SSatish Balay time_step = 0;
24349371c9d4SSatish Balay time = 0.;
24359371c9d4SSatish Balay }
2436dfa0de3dSJames Wright // Avoid "Duplicate child name found" error by not writing an already-written solution.
2437dfa0de3dSJames Wright // This usually occurs when a solution is written and then diverges on the very next timestep.
2438dfa0de3dSJames Wright if (time_step == cgv->previous_output_step) PetscFunctionReturn(PETSC_SUCCESS);
2439dfa0de3dSJames Wright
24405f34f2dcSJed Brown PetscCall(PetscSegBufferGet(cgv->output_times, 1, &time_slot));
24415f34f2dcSJed Brown *time_slot = time;
24429812b6beSJed Brown PetscCall(PetscSegBufferGet(cgv->output_steps, 1, &step_slot));
2443dfa0de3dSJames Wright *step_slot = cgv->previous_output_step = time_step;
24445f34f2dcSJed Brown PetscCall(PetscSNPrintf(solution_name, sizeof solution_name, "FlowSolution%" PetscInt_FMT, time_step));
24454c155f28SJames Wright PetscCallCGNSWrite(cg_sol_write(cgv->file_num, cgv->base, cgv->zone, solution_name, cgv->grid_loc, &sol), V, viewer);
24465f34f2dcSJed Brown PetscCall(VecGetArrayRead(V, &v));
244700a86070SJed Brown PetscCall(PetscSectionGetNumFields(section, &num_fields));
244800a86070SJed Brown for (PetscInt field = 0; field < num_fields; field++) {
244900a86070SJed Brown PetscInt ncomp;
24509bb8f83bSJed Brown const char *field_name;
24519bb8f83bSJed Brown PetscCall(PetscSectionGetFieldName(section, field, &field_name));
245200a86070SJed Brown PetscCall(PetscSectionGetFieldComponents(section, field, &ncomp));
24535f34f2dcSJed Brown for (PetscInt comp = 0; comp < ncomp; comp++) {
24545f34f2dcSJed Brown int cgfield;
24555f34f2dcSJed Brown const char *comp_name;
24569bb8f83bSJed Brown char cgns_field_name[32]; // CGNS max field name is 32
24575f34f2dcSJed Brown CGNS_ENUMT(DataType_t) datatype;
24585f34f2dcSJed Brown PetscCall(PetscSectionGetComponentName(section, field, comp, &comp_name));
245944698e90SJames Wright if (ncomp == 1 && comp_name[0] == '0' && comp_name[1] == '\0' && field_name[0] != '\0') PetscCall(PetscStrncpy(cgns_field_name, field_name, sizeof cgns_field_name));
24609bb8f83bSJed Brown else if (field_name[0] == '\0') PetscCall(PetscStrncpy(cgns_field_name, comp_name, sizeof cgns_field_name));
24619bb8f83bSJed Brown else PetscCall(PetscSNPrintf(cgns_field_name, sizeof cgns_field_name, "%s.%s", field_name, comp_name));
24625f34f2dcSJed Brown PetscCall(PetscCGNSDataType(PETSC_SCALAR, &datatype));
24634c155f28SJames Wright PetscCallCGNSWrite(cgp_field_write(cgv->file_num, cgv->base, cgv->zone, sol, datatype, cgns_field_name, &cgfield), V, viewer);
246400a86070SJed Brown for (PetscInt p = pStart, n = 0; p < pEnd; p++) {
246500a86070SJed Brown PetscInt off, dof;
246600a86070SJed Brown PetscCall(PetscSectionGetFieldDof(section, p, field, &dof));
246700a86070SJed Brown if (dof == 0) continue;
246800a86070SJed Brown PetscCall(PetscSectionGetFieldOffset(section, p, field, &off));
246900a86070SJed Brown for (PetscInt c = comp; c < dof; c += ncomp, n++) {
2470ec2db9e4SJames Wright switch (cgv->grid_loc) {
24719bb8f83bSJed Brown case CGNS_ENUMV(Vertex): {
24725f34f2dcSJed Brown PetscInt gn = cgv->node_l2g[n];
24735f34f2dcSJed Brown if (gn < cgv->nStart || cgv->nEnd <= gn) continue;
247400a86070SJed Brown cgv->nodal_field[gn - cgv->nStart] = v[off + c];
24759bb8f83bSJed Brown } break;
24769bb8f83bSJed Brown case CGNS_ENUMV(CellCenter): {
24779bb8f83bSJed Brown cgv->nodal_field[n] = v[off + c];
24789bb8f83bSJed Brown } break;
24799bb8f83bSJed Brown default:
24809bb8f83bSJed Brown SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only pack for Vertex and CellCenter grid locations");
24819bb8f83bSJed Brown }
248200a86070SJed Brown }
24835f34f2dcSJed Brown }
24845f34f2dcSJed Brown // CGNS nodes use 1-based indexing
2485ec2db9e4SJames Wright cgsize_t start, end;
2486ec2db9e4SJames Wright switch (cgv->grid_loc) {
2487ec2db9e4SJames Wright case CGNS_ENUMV(Vertex): {
2488ec2db9e4SJames Wright start = cgv->nStart + 1;
2489ec2db9e4SJames Wright end = cgv->nEnd;
2490ec2db9e4SJames Wright } break;
2491ec2db9e4SJames Wright case CGNS_ENUMV(CellCenter): {
24929bb8f83bSJed Brown start = cgv->eStart + 1;
24939bb8f83bSJed Brown end = cgv->eEnd;
2494ec2db9e4SJames Wright } break;
2495ec2db9e4SJames Wright default:
2496ec2db9e4SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only write for Vertex and CellCenter grid locations");
24979bb8f83bSJed Brown }
24984c155f28SJames Wright PetscCallCGNSWriteData(cgp_field_write_data(cgv->file_num, cgv->base, cgv->zone, sol, cgfield, &start, &end, cgv->nodal_field), V, viewer);
24995f34f2dcSJed Brown }
250000a86070SJed Brown }
25015f34f2dcSJed Brown PetscCall(VecRestoreArrayRead(V, &v));
250225760affSJed Brown PetscCall(PetscViewerCGNSCheckBatch_Internal(viewer));
25033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
25045f34f2dcSJed Brown }
2505472b9844SJames Wright
VecLoad_Plex_CGNS_Internal(Vec V,PetscViewer viewer)2506472b9844SJames Wright PetscErrorCode VecLoad_Plex_CGNS_Internal(Vec V, PetscViewer viewer)
2507472b9844SJames Wright {
2508472b9844SJames Wright MPI_Comm comm;
2509472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1];
2510472b9844SJames Wright PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data;
2511472b9844SJames Wright int cgid = cgv->file_num;
2512472b9844SJames Wright PetscBool use_parallel_viewer = PETSC_FALSE;
2513472b9844SJames Wright int z = 1; // Only support one zone
2514472b9844SJames Wright int B = 1; // Only support one base
2515472b9844SJames Wright int numComp;
2516472b9844SJames Wright PetscInt V_numComps, mystartv, myendv, myownedv;
2517472b9844SJames Wright
2518b30057acSJames Wright PetscFunctionBegin;
2519472b9844SJames Wright PetscCall(PetscObjectGetComm((PetscObject)V, &comm));
2520472b9844SJames Wright
2521472b9844SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_parallel", &use_parallel_viewer, NULL));
2522472b9844SJames Wright PetscCheck(use_parallel_viewer, comm, PETSC_ERR_USER_INPUT, "Cannot use VecLoad with CGNS file in serial reader; use -dm_plex_cgns_parallel to enable parallel reader");
2523472b9844SJames Wright
2524472b9844SJames Wright { // Get CGNS node ownership information
2525472b9844SJames Wright int nbases, nzones;
2526472b9844SJames Wright PetscInt NVertices;
2527472b9844SJames Wright PetscLayout vtx_map;
2528472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */
2529472b9844SJames Wright
25304c155f28SJames Wright PetscCallCGNSRead(cg_nbases(cgid, &nbases), V, viewer);
2531472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases);
25324c155f28SJames Wright PetscCallCGNSRead(cg_nzones(cgid, B, &nzones), V, viewer);
2533472b9844SJames Wright PetscCheck(nzones == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "limited to one zone %d", (int)nzones);
2534472b9844SJames Wright
25354c155f28SJames Wright PetscCallCGNSRead(cg_zone_read(cgid, B, z, buffer, sizes), V, viewer);
2536472b9844SJames Wright NVertices = sizes[0];
2537472b9844SJames Wright
2538472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NVertices, 1, &vtx_map));
2539472b9844SJames Wright PetscCall(PetscLayoutGetRange(vtx_map, &mystartv, &myendv));
2540472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(vtx_map, &myownedv));
2541472b9844SJames Wright PetscCall(PetscLayoutDestroy(&vtx_map));
2542472b9844SJames Wright }
2543472b9844SJames Wright
2544472b9844SJames Wright { // -- Read data from file into Vec
2545472b9844SJames Wright PetscScalar *fields = NULL;
2546472b9844SJames Wright PetscSF sfNatural;
2547472b9844SJames Wright
2548472b9844SJames Wright { // Check compatibility between sfNatural and the data source and sink
2549472b9844SJames Wright DM dm;
2550472b9844SJames Wright PetscInt nleaves, nroots, V_local_size;
2551472b9844SJames Wright
2552472b9844SJames Wright PetscCall(VecGetDM(V, &dm));
2553472b9844SJames Wright PetscCall(DMGetNaturalSF(dm, &sfNatural));
2554472b9844SJames Wright PetscCheck(sfNatural, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM of Vec must have sfNatural");
2555472b9844SJames Wright PetscCall(PetscSFGetGraph(sfNatural, &nroots, &nleaves, NULL, NULL));
2556472b9844SJames Wright PetscCall(VecGetLocalSize(V, &V_local_size));
2557472b9844SJames Wright PetscCheck(nleaves == myownedv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Number of locally owned vertices (% " PetscInt_FMT ") must match number of leaves in sfNatural (% " PetscInt_FMT ")", myownedv, nleaves);
2558d0bbc01eSJames Wright if (nroots == 0) {
2559d0bbc01eSJames Wright PetscCheck(V_local_size == nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Local Vec size (% " PetscInt_FMT ") must be zero if number of roots in sfNatural is zero", V_local_size);
2560d0bbc01eSJames Wright V_numComps = 0;
2561d0bbc01eSJames Wright } else {
2562472b9844SJames Wright PetscCheck(V_local_size % nroots == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Local Vec size (% " PetscInt_FMT ") not evenly divisible by number of roots in sfNatural (% " PetscInt_FMT ")", V_local_size, nroots);
2563472b9844SJames Wright V_numComps = V_local_size / nroots;
2564472b9844SJames Wright }
2565d0bbc01eSJames Wright }
2566472b9844SJames Wright
2567472b9844SJames Wright { // Read data into component-major ordering
2568472b9844SJames Wright int isol, numSols;
2569472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype;
2570472b9844SJames Wright double *fields_CGNS;
2571472b9844SJames Wright
25724c155f28SJames Wright PetscCallCGNSRead(cg_nsols(cgid, B, z, &numSols), V, viewer);
2573472b9844SJames Wright PetscCall(PetscViewerCGNSGetSolutionFileIndex_Internal(viewer, &isol));
25744c155f28SJames Wright PetscCallCGNSRead(cg_nfields(cgid, B, z, isol, &numComp), V, viewer);
2575d0bbc01eSJames Wright PetscCheck(V_numComps == numComp || V_numComps == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Vec sized for % " PetscInt_FMT " components per node, but file has %d components per node", V_numComps, numComp);
2576472b9844SJames Wright
2577472b9844SJames Wright cgsize_t range_min[3] = {mystartv + 1, 1, 1};
2578472b9844SJames Wright cgsize_t range_max[3] = {myendv, 1, 1};
2579472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * numComp, &fields_CGNS));
2580472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * numComp, &fields));
2581472b9844SJames Wright for (int d = 0; d < numComp; ++d) {
25824c155f28SJames Wright PetscCallCGNSRead(cg_field_info(cgid, B, z, isol, (d + 1), &datatype, buffer), V, viewer);
2583472b9844SJames Wright PetscCheck(datatype == CGNS_ENUMV(RealDouble), PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMETYPE, "Field %s in file is not of type double", buffer);
25844c155f28SJames Wright PetscCallCGNSReadData(cgp_field_read_data(cgid, B, z, isol, (d + 1), range_min, range_max, &fields_CGNS[d * myownedv]), V, viewer);
2585472b9844SJames Wright }
2586472b9844SJames Wright for (int d = 0; d < numComp; ++d) {
2587472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) fields[v * numComp + d] = fields_CGNS[d * myownedv + v];
2588472b9844SJames Wright }
2589472b9844SJames Wright PetscCall(PetscFree(fields_CGNS));
2590472b9844SJames Wright }
2591472b9844SJames Wright
2592472b9844SJames Wright { // Reduce fields into Vec array
2593472b9844SJames Wright PetscScalar *V_array;
2594472b9844SJames Wright MPI_Datatype fieldtype;
2595472b9844SJames Wright
2596472b9844SJames Wright PetscCall(VecGetArrayWrite(V, &V_array));
2597472b9844SJames Wright PetscCallMPI(MPI_Type_contiguous(numComp, MPIU_SCALAR, &fieldtype));
2598472b9844SJames Wright PetscCallMPI(MPI_Type_commit(&fieldtype));
2599472b9844SJames Wright PetscCall(PetscSFReduceBegin(sfNatural, fieldtype, fields, V_array, MPI_REPLACE));
2600472b9844SJames Wright PetscCall(PetscSFReduceEnd(sfNatural, fieldtype, fields, V_array, MPI_REPLACE));
2601472b9844SJames Wright PetscCallMPI(MPI_Type_free(&fieldtype));
2602472b9844SJames Wright PetscCall(VecRestoreArrayWrite(V, &V_array));
2603472b9844SJames Wright }
2604472b9844SJames Wright PetscCall(PetscFree(fields));
2605472b9844SJames Wright }
2606472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS);
2607472b9844SJames Wright }
2608