xref: /petsc/src/dm/impls/plex/cgns/plexcgns2.c (revision d9126033840fa4b9e125cadad06c85976e6bf099)
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, &sectionCellTypes));
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, &sectionCellTypes[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, &section_));
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, &sectionBuffer));
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(&sectionBuffer));
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, &sectionsf));
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, &section), 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, &section), 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, &section));
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