15f34f2dcSJed Brown #define PETSCDM_DLL 25f34f2dcSJed Brown #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 35f34f2dcSJed Brown #include <petsc/private/viewercgnsimpl.h> 45f34f2dcSJed Brown 55f34f2dcSJed Brown #include <pcgnslib.h> 65f34f2dcSJed Brown #include <cgns_io.h> 75f34f2dcSJed Brown 85f34f2dcSJed Brown #if !defined(CGNS_ENUMT) 95f34f2dcSJed Brown #define CGNS_ENUMT(a) a 105f34f2dcSJed Brown #endif 115f34f2dcSJed Brown #if !defined(CGNS_ENUMV) 125f34f2dcSJed Brown #define CGNS_ENUMV(a) a 135f34f2dcSJed Brown #endif 145f34f2dcSJed Brown // Permute plex closure ordering to CGNS 15d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCGNSGetPermutation_Internal(DMPolytopeType cell_type, PetscInt closure_size, CGNS_ENUMT(ElementType_t) * element_type, const int **perm) 16d71ae5a4SJacob Faibussowitsch { 17*472b9844SJames Wright CGNS_ENUMT(ElementType_t) element_type_tmp; 18*472b9844SJames Wright 19*472b9844SJames Wright // https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid 205f34f2dcSJed Brown static const int bar_2[2] = {0, 1}; 215f34f2dcSJed Brown static const int bar_3[3] = {1, 2, 0}; 225f34f2dcSJed Brown static const int bar_4[4] = {2, 3, 0, 1}; 235f34f2dcSJed Brown static const int bar_5[5] = {3, 4, 0, 1, 2}; 245f34f2dcSJed Brown static const int tri_3[3] = {0, 1, 2}; 255f34f2dcSJed Brown static const int tri_6[6] = {3, 4, 5, 0, 1, 2}; 265f34f2dcSJed Brown static const int tri_10[10] = {7, 8, 9, 1, 2, 3, 4, 5, 6, 0}; 275f34f2dcSJed Brown static const int quad_4[4] = {0, 1, 2, 3}; 285f34f2dcSJed Brown static const int quad_9[9] = { 295f34f2dcSJed Brown 5, 6, 7, 8, // vertices 305f34f2dcSJed Brown 1, 2, 3, 4, // edges 315f34f2dcSJed Brown 0, // center 325f34f2dcSJed Brown }; 335f34f2dcSJed Brown static const int quad_16[] = { 345f34f2dcSJed Brown 12, 13, 14, 15, // vertices 355f34f2dcSJed Brown 4, 5, 6, 7, 8, 9, 10, 11, // edges 365f34f2dcSJed Brown 0, 1, 3, 2, // centers 375f34f2dcSJed Brown }; 385f34f2dcSJed Brown static const int quad_25[] = { 395f34f2dcSJed Brown 21, 22, 23, 24, // vertices 405f34f2dcSJed Brown 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, // edges 415f34f2dcSJed Brown 0, 1, 2, 5, 8, 7, 6, 3, 4, // centers 425f34f2dcSJed Brown }; 435f34f2dcSJed Brown static const int tetra_4[4] = {0, 2, 1, 3}; 445f34f2dcSJed Brown static const int tetra_10[10] = {6, 8, 7, 9, 2, 1, 0, 3, 5, 4}; 455f34f2dcSJed Brown static const int tetra_20[20] = { 465f34f2dcSJed Brown 16, 18, 17, 19, // vertices 475f34f2dcSJed Brown 9, 8, 7, 6, 5, 4, // bottom edges 485f34f2dcSJed Brown 10, 11, 14, 15, 13, 12, // side edges 495f34f2dcSJed Brown 0, 2, 3, 1, // faces 505f34f2dcSJed Brown }; 515f34f2dcSJed Brown static const int hexa_8[8] = {0, 3, 2, 1, 4, 5, 6, 7}; 525f34f2dcSJed Brown static const int hexa_27[27] = { 535f34f2dcSJed Brown 19, 22, 21, 20, 23, 24, 25, 26, // vertices 545f34f2dcSJed Brown 10, 9, 8, 7, // bottom edges 555f34f2dcSJed Brown 16, 15, 18, 17, // mid edges 565f34f2dcSJed Brown 11, 12, 13, 14, // top edges 575f34f2dcSJed Brown 1, 3, 5, 4, 6, 2, // faces 585f34f2dcSJed Brown 0, // center 595f34f2dcSJed Brown }; 609371c9d4SSatish Balay static const int hexa_64[64] = { 619371c9d4SSatish 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 625f34f2dcSJed Brown 56, 59, 58, 57, 60, 61, 62, 63, // vertices 635f34f2dcSJed Brown 39, 38, 37, 36, 35, 34, 33, 32, // bottom edges 645f34f2dcSJed Brown 51, 50, 48, 49, 52, 53, 55, 54, // mid edges; Paraview needs edge 21-22 swapped with 23-24 655f34f2dcSJed Brown 40, 41, 42, 43, 44, 45, 46, 47, // top edges 665f34f2dcSJed Brown 8, 10, 11, 9, // z-minus face 675f34f2dcSJed Brown 16, 17, 19, 18, // y-minus face 685f34f2dcSJed Brown 24, 25, 27, 26, // x-plus face 695f34f2dcSJed Brown 20, 21, 23, 22, // y-plus face 705f34f2dcSJed Brown 30, 28, 29, 31, // x-minus face 715f34f2dcSJed Brown 12, 13, 15, 14, // z-plus face 725f34f2dcSJed Brown 0, 1, 3, 2, 4, 5, 7, 6, // center 735f34f2dcSJed Brown }; 745f34f2dcSJed Brown 755f34f2dcSJed Brown PetscFunctionBegin; 76*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(ElementTypeNull); 775f34f2dcSJed Brown *perm = NULL; 785f34f2dcSJed Brown switch (cell_type) { 795f34f2dcSJed Brown case DM_POLYTOPE_SEGMENT: 805f34f2dcSJed Brown switch (closure_size) { 81d71ae5a4SJacob Faibussowitsch case 2: 82*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_2); 83d71ae5a4SJacob Faibussowitsch *perm = bar_2; 84d71ae5a4SJacob Faibussowitsch case 3: 85*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_3); 86d71ae5a4SJacob Faibussowitsch *perm = bar_3; 875f34f2dcSJed Brown case 4: 88*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_4); 895f34f2dcSJed Brown *perm = bar_4; 905f34f2dcSJed Brown break; 915f34f2dcSJed Brown case 5: 92*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(BAR_5); 935f34f2dcSJed Brown *perm = bar_5; 945f34f2dcSJed Brown break; 95d71ae5a4SJacob Faibussowitsch default: 96d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 975f34f2dcSJed Brown } 985f34f2dcSJed Brown break; 995f34f2dcSJed Brown case DM_POLYTOPE_TRIANGLE: 1005f34f2dcSJed Brown switch (closure_size) { 1015f34f2dcSJed Brown case 3: 102*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_3); 1035f34f2dcSJed Brown *perm = tri_3; 1045f34f2dcSJed Brown break; 1055f34f2dcSJed Brown case 6: 106*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_6); 1075f34f2dcSJed Brown *perm = tri_6; 1085f34f2dcSJed Brown break; 1095f34f2dcSJed Brown case 10: 110*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TRI_10); 1115f34f2dcSJed Brown *perm = tri_10; 1125f34f2dcSJed Brown break; 113d71ae5a4SJacob Faibussowitsch default: 114d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 1155f34f2dcSJed Brown } 1165f34f2dcSJed Brown break; 1175f34f2dcSJed Brown case DM_POLYTOPE_QUADRILATERAL: 1185f34f2dcSJed Brown switch (closure_size) { 1195f34f2dcSJed Brown case 4: 120*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_4); 1215f34f2dcSJed Brown *perm = quad_4; 1225f34f2dcSJed Brown break; 1235f34f2dcSJed Brown case 9: 124*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_9); 1255f34f2dcSJed Brown *perm = quad_9; 1265f34f2dcSJed Brown break; 1275f34f2dcSJed Brown case 16: 128*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_16); 1295f34f2dcSJed Brown *perm = quad_16; 1305f34f2dcSJed Brown break; 1315f34f2dcSJed Brown case 25: 132*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(QUAD_25); 1335f34f2dcSJed Brown *perm = quad_25; 1345f34f2dcSJed Brown break; 135d71ae5a4SJacob Faibussowitsch default: 136d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 1375f34f2dcSJed Brown } 1385f34f2dcSJed Brown break; 1395f34f2dcSJed Brown case DM_POLYTOPE_TETRAHEDRON: 1405f34f2dcSJed Brown switch (closure_size) { 1415f34f2dcSJed Brown case 4: 142*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_4); 1435f34f2dcSJed Brown *perm = tetra_4; 1445f34f2dcSJed Brown break; 1455f34f2dcSJed Brown case 10: 146*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_10); 1475f34f2dcSJed Brown *perm = tetra_10; 1485f34f2dcSJed Brown break; 1495f34f2dcSJed Brown case 20: 150*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(TETRA_20); 1515f34f2dcSJed Brown *perm = tetra_20; 1525f34f2dcSJed Brown break; 153d71ae5a4SJacob Faibussowitsch default: 154d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 1555f34f2dcSJed Brown } 1565f34f2dcSJed Brown break; 1575f34f2dcSJed Brown case DM_POLYTOPE_HEXAHEDRON: 1585f34f2dcSJed Brown switch (closure_size) { 1595f34f2dcSJed Brown case 8: 160*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_8); 1615f34f2dcSJed Brown *perm = hexa_8; 1625f34f2dcSJed Brown break; 1635f34f2dcSJed Brown case 27: 164*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_27); 1655f34f2dcSJed Brown *perm = hexa_27; 1665f34f2dcSJed Brown break; 1675f34f2dcSJed Brown case 64: 168*472b9844SJames Wright element_type_tmp = CGNS_ENUMV(HEXA_64); 1695f34f2dcSJed Brown *perm = hexa_64; 1705f34f2dcSJed Brown break; 171d71ae5a4SJacob Faibussowitsch default: 172d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 1735f34f2dcSJed Brown } 1745f34f2dcSJed Brown break; 175d71ae5a4SJacob Faibussowitsch default: 176d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cell type %s with closure size %" PetscInt_FMT, DMPolytopeTypes[cell_type], closure_size); 1775f34f2dcSJed Brown } 178*472b9844SJames Wright if (element_type) *element_type = element_type_tmp; 179*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 180*472b9844SJames Wright } 181*472b9844SJames Wright 182*472b9844SJames Wright /* 183*472b9844SJames Wright Input Parameters: 184*472b9844SJames Wright + cellType - The CGNS-defined element type 185*472b9844SJames Wright 186*472b9844SJames Wright Output Parameters: 187*472b9844SJames Wright + dmcelltype - The equivalent DMPolytopeType for the cellType 188*472b9844SJames Wright . numCorners - Number of corners of the polytope 189*472b9844SJames Wright - dim - The topological dimension of the polytope 190*472b9844SJames Wright 191*472b9844SJames Wright CGNS elements defined in: https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid 192*472b9844SJames Wright */ 193*472b9844SJames Wright static inline PetscErrorCode CGNSElementTypeGetTopologyInfo(CGNS_ENUMT(ElementType_t) cellType, DMPolytopeType *dmcelltype, PetscInt *numCorners, PetscInt *dim) 194*472b9844SJames Wright { 195*472b9844SJames Wright DMPolytopeType _dmcelltype; 196*472b9844SJames Wright 197*472b9844SJames Wright PetscFunctionBeginUser; 198*472b9844SJames Wright switch (cellType) { 199*472b9844SJames Wright case CGNS_ENUMV(BAR_2): 200*472b9844SJames Wright case CGNS_ENUMV(BAR_3): 201*472b9844SJames Wright case CGNS_ENUMV(BAR_4): 202*472b9844SJames Wright case CGNS_ENUMV(BAR_5): 203*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_SEGMENT; 204*472b9844SJames Wright break; 205*472b9844SJames Wright case CGNS_ENUMV(TRI_3): 206*472b9844SJames Wright case CGNS_ENUMV(TRI_6): 207*472b9844SJames Wright case CGNS_ENUMV(TRI_9): 208*472b9844SJames Wright case CGNS_ENUMV(TRI_10): 209*472b9844SJames Wright case CGNS_ENUMV(TRI_12): 210*472b9844SJames Wright case CGNS_ENUMV(TRI_15): 211*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TRIANGLE; 212*472b9844SJames Wright break; 213*472b9844SJames Wright case CGNS_ENUMV(QUAD_4): 214*472b9844SJames Wright case CGNS_ENUMV(QUAD_8): 215*472b9844SJames Wright case CGNS_ENUMV(QUAD_9): 216*472b9844SJames Wright case CGNS_ENUMV(QUAD_12): 217*472b9844SJames Wright case CGNS_ENUMV(QUAD_16): 218*472b9844SJames Wright case CGNS_ENUMV(QUAD_P4_16): 219*472b9844SJames Wright case CGNS_ENUMV(QUAD_25): 220*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_QUADRILATERAL; 221*472b9844SJames Wright break; 222*472b9844SJames Wright case CGNS_ENUMV(TETRA_4): 223*472b9844SJames Wright case CGNS_ENUMV(TETRA_10): 224*472b9844SJames Wright case CGNS_ENUMV(TETRA_16): 225*472b9844SJames Wright case CGNS_ENUMV(TETRA_20): 226*472b9844SJames Wright case CGNS_ENUMV(TETRA_22): 227*472b9844SJames Wright case CGNS_ENUMV(TETRA_34): 228*472b9844SJames Wright case CGNS_ENUMV(TETRA_35): 229*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TETRAHEDRON; 230*472b9844SJames Wright break; 231*472b9844SJames Wright case CGNS_ENUMV(PYRA_5): 232*472b9844SJames Wright case CGNS_ENUMV(PYRA_13): 233*472b9844SJames Wright case CGNS_ENUMV(PYRA_14): 234*472b9844SJames Wright case CGNS_ENUMV(PYRA_21): 235*472b9844SJames Wright case CGNS_ENUMV(PYRA_29): 236*472b9844SJames Wright case CGNS_ENUMV(PYRA_P4_29): 237*472b9844SJames Wright case CGNS_ENUMV(PYRA_30): 238*472b9844SJames Wright case CGNS_ENUMV(PYRA_50): 239*472b9844SJames Wright case CGNS_ENUMV(PYRA_55): 240*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_PYRAMID; 241*472b9844SJames Wright break; 242*472b9844SJames Wright case CGNS_ENUMV(PENTA_6): 243*472b9844SJames Wright case CGNS_ENUMV(PENTA_15): 244*472b9844SJames Wright case CGNS_ENUMV(PENTA_18): 245*472b9844SJames Wright case CGNS_ENUMV(PENTA_24): 246*472b9844SJames Wright case CGNS_ENUMV(PENTA_33): 247*472b9844SJames Wright case CGNS_ENUMV(PENTA_38): 248*472b9844SJames Wright case CGNS_ENUMV(PENTA_40): 249*472b9844SJames Wright case CGNS_ENUMV(PENTA_66): 250*472b9844SJames Wright case CGNS_ENUMV(PENTA_75): 251*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_TRI_PRISM; 252*472b9844SJames Wright break; 253*472b9844SJames Wright case CGNS_ENUMV(HEXA_8): 254*472b9844SJames Wright case CGNS_ENUMV(HEXA_20): 255*472b9844SJames Wright case CGNS_ENUMV(HEXA_27): 256*472b9844SJames Wright case CGNS_ENUMV(HEXA_32): 257*472b9844SJames Wright case CGNS_ENUMV(HEXA_44): 258*472b9844SJames Wright case CGNS_ENUMV(HEXA_56): 259*472b9844SJames Wright case CGNS_ENUMV(HEXA_64): 260*472b9844SJames Wright case CGNS_ENUMV(HEXA_98): 261*472b9844SJames Wright case CGNS_ENUMV(HEXA_125): 262*472b9844SJames Wright _dmcelltype = DM_POLYTOPE_HEXAHEDRON; 263*472b9844SJames Wright break; 264*472b9844SJames Wright case CGNS_ENUMV(MIXED): 265*472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: MIXED"); 266*472b9844SJames Wright default: 267*472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: %d", (int)cellType); 268*472b9844SJames Wright } 269*472b9844SJames Wright 270*472b9844SJames Wright if (dmcelltype) *dmcelltype = _dmcelltype; 271*472b9844SJames Wright if (numCorners) *numCorners = DMPolytopeTypeGetNumVertices(_dmcelltype); 272*472b9844SJames Wright if (dim) *dim = DMPolytopeTypeGetDim(_dmcelltype); 273*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 274*472b9844SJames Wright } 275*472b9844SJames Wright 276*472b9844SJames Wright /* 277*472b9844SJames Wright Input Parameters: 278*472b9844SJames Wright + cellType - The CGNS-defined cell type 279*472b9844SJames Wright 280*472b9844SJames Wright Output Parameters: 281*472b9844SJames Wright + numClosure - Number of nodes that define the function space on the cell 282*472b9844SJames Wright - pOrder - The polynomial order of the cell 283*472b9844SJames Wright 284*472b9844SJames Wright CGNS elements defined in: https://cgns.github.io/CGNS_docs_current/sids/conv.html#unstructgrid 285*472b9844SJames Wright 286*472b9844SJames Wright Note: we only support "full" elements, ie. not seredipity elements 287*472b9844SJames Wright */ 288*472b9844SJames Wright static inline PetscErrorCode CGNSElementTypeGetDiscretizationInfo(CGNS_ENUMT(ElementType_t) cellType, PetscInt *numClosure, PetscInt *pOrder) 289*472b9844SJames Wright { 290*472b9844SJames Wright PetscInt _numClosure, _pOrder; 291*472b9844SJames Wright 292*472b9844SJames Wright PetscFunctionBeginUser; 293*472b9844SJames Wright switch (cellType) { 294*472b9844SJames Wright case CGNS_ENUMV(BAR_2): 295*472b9844SJames Wright _numClosure = 2; 296*472b9844SJames Wright _pOrder = 1; 297*472b9844SJames Wright break; 298*472b9844SJames Wright case CGNS_ENUMV(BAR_3): 299*472b9844SJames Wright _numClosure = 3; 300*472b9844SJames Wright _pOrder = 2; 301*472b9844SJames Wright break; 302*472b9844SJames Wright case CGNS_ENUMV(BAR_4): 303*472b9844SJames Wright _numClosure = 4; 304*472b9844SJames Wright _pOrder = 3; 305*472b9844SJames Wright break; 306*472b9844SJames Wright case CGNS_ENUMV(BAR_5): 307*472b9844SJames Wright _numClosure = 5; 308*472b9844SJames Wright _pOrder = 4; 309*472b9844SJames Wright break; 310*472b9844SJames Wright case CGNS_ENUMV(TRI_3): 311*472b9844SJames Wright _numClosure = 3; 312*472b9844SJames Wright _pOrder = 1; 313*472b9844SJames Wright break; 314*472b9844SJames Wright case CGNS_ENUMV(TRI_6): 315*472b9844SJames Wright _numClosure = 6; 316*472b9844SJames Wright _pOrder = 2; 317*472b9844SJames Wright break; 318*472b9844SJames Wright case CGNS_ENUMV(TRI_10): 319*472b9844SJames Wright _numClosure = 10; 320*472b9844SJames Wright _pOrder = 3; 321*472b9844SJames Wright break; 322*472b9844SJames Wright case CGNS_ENUMV(TRI_15): 323*472b9844SJames Wright _numClosure = 15; 324*472b9844SJames Wright _pOrder = 4; 325*472b9844SJames Wright break; 326*472b9844SJames Wright case CGNS_ENUMV(QUAD_4): 327*472b9844SJames Wright _numClosure = 4; 328*472b9844SJames Wright _pOrder = 1; 329*472b9844SJames Wright break; 330*472b9844SJames Wright case CGNS_ENUMV(QUAD_9): 331*472b9844SJames Wright _numClosure = 9; 332*472b9844SJames Wright _pOrder = 2; 333*472b9844SJames Wright break; 334*472b9844SJames Wright case CGNS_ENUMV(QUAD_16): 335*472b9844SJames Wright _numClosure = 16; 336*472b9844SJames Wright _pOrder = 3; 337*472b9844SJames Wright break; 338*472b9844SJames Wright case CGNS_ENUMV(QUAD_25): 339*472b9844SJames Wright _numClosure = 25; 340*472b9844SJames Wright _pOrder = 4; 341*472b9844SJames Wright break; 342*472b9844SJames Wright case CGNS_ENUMV(TETRA_4): 343*472b9844SJames Wright _numClosure = 4; 344*472b9844SJames Wright _pOrder = 1; 345*472b9844SJames Wright break; 346*472b9844SJames Wright case CGNS_ENUMV(TETRA_10): 347*472b9844SJames Wright _numClosure = 10; 348*472b9844SJames Wright _pOrder = 2; 349*472b9844SJames Wright break; 350*472b9844SJames Wright case CGNS_ENUMV(TETRA_20): 351*472b9844SJames Wright _numClosure = 20; 352*472b9844SJames Wright _pOrder = 3; 353*472b9844SJames Wright break; 354*472b9844SJames Wright case CGNS_ENUMV(TETRA_35): 355*472b9844SJames Wright _numClosure = 35; 356*472b9844SJames Wright _pOrder = 4; 357*472b9844SJames Wright break; 358*472b9844SJames Wright case CGNS_ENUMV(PYRA_5): 359*472b9844SJames Wright _numClosure = 5; 360*472b9844SJames Wright _pOrder = 1; 361*472b9844SJames Wright break; 362*472b9844SJames Wright case CGNS_ENUMV(PYRA_14): 363*472b9844SJames Wright _numClosure = 14; 364*472b9844SJames Wright _pOrder = 2; 365*472b9844SJames Wright break; 366*472b9844SJames Wright case CGNS_ENUMV(PYRA_30): 367*472b9844SJames Wright _numClosure = 30; 368*472b9844SJames Wright _pOrder = 3; 369*472b9844SJames Wright break; 370*472b9844SJames Wright case CGNS_ENUMV(PYRA_55): 371*472b9844SJames Wright _numClosure = 55; 372*472b9844SJames Wright _pOrder = 4; 373*472b9844SJames Wright break; 374*472b9844SJames Wright case CGNS_ENUMV(PENTA_6): 375*472b9844SJames Wright _numClosure = 6; 376*472b9844SJames Wright _pOrder = 1; 377*472b9844SJames Wright break; 378*472b9844SJames Wright case CGNS_ENUMV(PENTA_18): 379*472b9844SJames Wright _numClosure = 18; 380*472b9844SJames Wright _pOrder = 2; 381*472b9844SJames Wright break; 382*472b9844SJames Wright case CGNS_ENUMV(PENTA_40): 383*472b9844SJames Wright _numClosure = 40; 384*472b9844SJames Wright _pOrder = 3; 385*472b9844SJames Wright break; 386*472b9844SJames Wright case CGNS_ENUMV(PENTA_75): 387*472b9844SJames Wright _numClosure = 75; 388*472b9844SJames Wright _pOrder = 4; 389*472b9844SJames Wright break; 390*472b9844SJames Wright case CGNS_ENUMV(HEXA_8): 391*472b9844SJames Wright _numClosure = 8; 392*472b9844SJames Wright _pOrder = 1; 393*472b9844SJames Wright break; 394*472b9844SJames Wright case CGNS_ENUMV(HEXA_27): 395*472b9844SJames Wright _numClosure = 27; 396*472b9844SJames Wright _pOrder = 2; 397*472b9844SJames Wright break; 398*472b9844SJames Wright case CGNS_ENUMV(HEXA_64): 399*472b9844SJames Wright _numClosure = 64; 400*472b9844SJames Wright _pOrder = 3; 401*472b9844SJames Wright break; 402*472b9844SJames Wright case CGNS_ENUMV(HEXA_125): 403*472b9844SJames Wright _numClosure = 125; 404*472b9844SJames Wright _pOrder = 4; 405*472b9844SJames Wright break; 406*472b9844SJames Wright case CGNS_ENUMV(MIXED): 407*472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid CGNS ElementType_t: MIXED"); 408*472b9844SJames Wright default: 409*472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported or Invalid cell type %d", (int)cellType); 410*472b9844SJames Wright } 411*472b9844SJames Wright if (numClosure) *numClosure = _numClosure; 412*472b9844SJames Wright if (pOrder) *pOrder = _pOrder; 413*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 414*472b9844SJames Wright } 415*472b9844SJames Wright 416*472b9844SJames Wright static PetscErrorCode PetscCGNSDataType(PetscDataType pd, CGNS_ENUMT(DataType_t) * cd) 417*472b9844SJames Wright { 418*472b9844SJames Wright PetscFunctionBegin; 419*472b9844SJames Wright switch (pd) { 420*472b9844SJames Wright case PETSC_FLOAT: 421*472b9844SJames Wright *cd = CGNS_ENUMV(RealSingle); 422*472b9844SJames Wright break; 423*472b9844SJames Wright case PETSC_DOUBLE: 424*472b9844SJames Wright *cd = CGNS_ENUMV(RealDouble); 425*472b9844SJames Wright break; 426*472b9844SJames Wright case PETSC_COMPLEX: 427*472b9844SJames Wright *cd = CGNS_ENUMV(ComplexDouble); 428*472b9844SJames Wright break; 429*472b9844SJames Wright default: 430*472b9844SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Data type %s", PetscDataTypes[pd]); 431*472b9844SJames Wright } 432*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 433*472b9844SJames Wright } 434*472b9844SJames Wright 435*472b9844SJames Wright PetscErrorCode DMPlexCreateCGNSFromFile_Internal(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 436*472b9844SJames Wright { 437*472b9844SJames Wright int cgid = -1; 438*472b9844SJames Wright PetscBool use_parallel_viewer = PETSC_FALSE; 439*472b9844SJames Wright 440*472b9844SJames Wright PetscFunctionBegin; 441*472b9844SJames Wright PetscAssertPointer(filename, 2); 442*472b9844SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_parallel", &use_parallel_viewer, NULL)); 443*472b9844SJames Wright 444*472b9844SJames Wright if (use_parallel_viewer) { 445*472b9844SJames Wright PetscCallCGNS(cgp_mpi_comm(comm)); 446*472b9844SJames Wright PetscCallCGNS(cgp_open(filename, CG_MODE_READ, &cgid)); 447*472b9844SJames Wright PetscCheck(cgid > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "cgp_open(\"%s\",...) did not return a valid file ID", filename); 448*472b9844SJames Wright PetscCall(DMPlexCreateCGNS(comm, cgid, interpolate, dm)); 449*472b9844SJames Wright PetscCallCGNS(cgp_close(cgid)); 450*472b9844SJames Wright } else { 451*472b9844SJames Wright PetscCallCGNS(cg_open(filename, CG_MODE_READ, &cgid)); 452*472b9844SJames Wright PetscCheck(cgid > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "cg_open(\"%s\",...) did not return a valid file ID", filename); 453*472b9844SJames Wright PetscCall(DMPlexCreateCGNS(comm, cgid, interpolate, dm)); 454*472b9844SJames Wright PetscCallCGNS(cg_close(cgid)); 455*472b9844SJames Wright } 456*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 457*472b9844SJames Wright } 458*472b9844SJames Wright 459*472b9844SJames Wright PetscErrorCode DMPlexCreateCGNS_Internal_Serial(MPI_Comm comm, PetscInt cgid, PetscBool interpolate, DM *dm) 460*472b9844SJames Wright { 461*472b9844SJames Wright PetscMPIInt num_proc, rank; 462*472b9844SJames Wright DM cdm; 463*472b9844SJames Wright DMLabel label; 464*472b9844SJames Wright PetscSection coordSection; 465*472b9844SJames Wright Vec coordinates; 466*472b9844SJames Wright PetscScalar *coords; 467*472b9844SJames Wright PetscInt *cellStart, *vertStart, v; 468*472b9844SJames Wright PetscInt labelIdRange[2], labelId; 469*472b9844SJames Wright /* Read from file */ 470*472b9844SJames Wright char basename[CGIO_MAX_NAME_LENGTH + 1]; 471*472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1]; 472*472b9844SJames Wright int dim = 0, physDim = 0, coordDim = 0, numVertices = 0, numCells = 0; 473*472b9844SJames Wright int nzones = 0; 474*472b9844SJames Wright const int B = 1; // Only support single base 475*472b9844SJames Wright 476*472b9844SJames Wright PetscFunctionBegin; 477*472b9844SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank)); 478*472b9844SJames Wright PetscCallMPI(MPI_Comm_size(comm, &num_proc)); 479*472b9844SJames Wright PetscCall(DMCreate(comm, dm)); 480*472b9844SJames Wright PetscCall(DMSetType(*dm, DMPLEX)); 481*472b9844SJames Wright 482*472b9844SJames Wright /* Open CGNS II file and read basic information on rank 0, then broadcast to all processors */ 483*472b9844SJames Wright if (rank == 0) { 484*472b9844SJames Wright int nbases, z; 485*472b9844SJames Wright 486*472b9844SJames Wright PetscCallCGNS(cg_nbases(cgid, &nbases)); 487*472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases); 488*472b9844SJames Wright PetscCallCGNS(cg_base_read(cgid, B, basename, &dim, &physDim)); 489*472b9844SJames Wright PetscCallCGNS(cg_nzones(cgid, B, &nzones)); 490*472b9844SJames Wright PetscCall(PetscCalloc2(nzones + 1, &cellStart, nzones + 1, &vertStart)); 491*472b9844SJames Wright for (z = 1; z <= nzones; ++z) { 492*472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */ 493*472b9844SJames Wright 494*472b9844SJames Wright PetscCallCGNS(cg_zone_read(cgid, B, z, buffer, sizes)); 495*472b9844SJames Wright numVertices += sizes[0]; 496*472b9844SJames Wright numCells += sizes[1]; 497*472b9844SJames Wright cellStart[z] += sizes[1] + cellStart[z - 1]; 498*472b9844SJames Wright vertStart[z] += sizes[0] + vertStart[z - 1]; 499*472b9844SJames Wright } 500*472b9844SJames Wright for (z = 1; z <= nzones; ++z) vertStart[z] += numCells; 501*472b9844SJames Wright coordDim = dim; 502*472b9844SJames Wright } 503*472b9844SJames Wright PetscCallMPI(MPI_Bcast(basename, CGIO_MAX_NAME_LENGTH + 1, MPI_CHAR, 0, comm)); 504*472b9844SJames Wright PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm)); 505*472b9844SJames Wright PetscCallMPI(MPI_Bcast(&coordDim, 1, MPI_INT, 0, comm)); 506*472b9844SJames Wright PetscCallMPI(MPI_Bcast(&nzones, 1, MPI_INT, 0, comm)); 507*472b9844SJames Wright 508*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)*dm, basename)); 509*472b9844SJames Wright PetscCall(DMSetDimension(*dm, dim)); 510*472b9844SJames Wright PetscCall(DMCreateLabel(*dm, "celltype")); 511*472b9844SJames Wright PetscCall(DMPlexSetChart(*dm, 0, numCells + numVertices)); 512*472b9844SJames Wright 513*472b9844SJames Wright /* Read zone information */ 514*472b9844SJames Wright if (rank == 0) { 515*472b9844SJames Wright int z, c, c_loc; 516*472b9844SJames Wright 517*472b9844SJames Wright /* Read the cell set connectivity table and build mesh topology 518*472b9844SJames Wright CGNS standard requires that cells in a zone be numbered sequentially and be pairwise disjoint. */ 519*472b9844SJames Wright /* First set sizes */ 520*472b9844SJames Wright for (z = 1, c = 0; z <= nzones; ++z) { 521*472b9844SJames Wright CGNS_ENUMT(ZoneType_t) zonetype; 522*472b9844SJames Wright int nsections; 523*472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType; 524*472b9844SJames Wright cgsize_t start, end; 525*472b9844SJames Wright int nbndry, parentFlag; 526*472b9844SJames Wright PetscInt numCorners, pOrder; 527*472b9844SJames Wright DMPolytopeType ctype; 528*472b9844SJames Wright const int S = 1; // Only support single section 529*472b9844SJames Wright 530*472b9844SJames Wright PetscCallCGNS(cg_zone_type(cgid, B, z, &zonetype)); 531*472b9844SJames Wright PetscCheck(zonetype != CGNS_ENUMV(Structured), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can only handle Unstructured zones for CGNS"); 532*472b9844SJames Wright PetscCallCGNS(cg_nsections(cgid, B, z, &nsections)); 533*472b9844SJames Wright PetscCheck(nsections <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single section, not %d", nsections); 534*472b9844SJames Wright PetscCallCGNS(cg_section_read(cgid, B, z, S, buffer, &cellType, &start, &end, &nbndry, &parentFlag)); 535*472b9844SJames Wright if (cellType == CGNS_ENUMV(MIXED)) { 536*472b9844SJames Wright cgsize_t elementDataSize, *elements; 537*472b9844SJames Wright PetscInt off; 538*472b9844SJames Wright 539*472b9844SJames Wright PetscCallCGNS(cg_ElementDataSize(cgid, B, z, S, &elementDataSize)); 540*472b9844SJames Wright PetscCall(PetscMalloc1(elementDataSize, &elements)); 541*472b9844SJames Wright PetscCallCGNS(cg_poly_elements_read(cgid, B, z, S, elements, NULL, NULL)); 542*472b9844SJames Wright for (c_loc = start, off = 0; c_loc <= end; ++c_loc, ++c) { 543*472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(elements[off], &ctype, &numCorners, NULL)); 544*472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(elements[off], NULL, &pOrder)); 545*472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder); 546*472b9844SJames Wright PetscCall(DMPlexSetConeSize(*dm, c, numCorners)); 547*472b9844SJames Wright PetscCall(DMPlexSetCellType(*dm, c, ctype)); 548*472b9844SJames Wright off += numCorners + 1; 549*472b9844SJames Wright } 550*472b9844SJames Wright PetscCall(PetscFree(elements)); 551*472b9844SJames Wright } else { 552*472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, &ctype, &numCorners, NULL)); 553*472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, NULL, &pOrder)); 554*472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder); 555*472b9844SJames Wright for (c_loc = start; c_loc <= end; ++c_loc, ++c) { 556*472b9844SJames Wright PetscCall(DMPlexSetConeSize(*dm, c, numCorners)); 557*472b9844SJames Wright PetscCall(DMPlexSetCellType(*dm, c, ctype)); 558*472b9844SJames Wright } 559*472b9844SJames Wright } 560*472b9844SJames Wright } 561*472b9844SJames Wright for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT)); 562*472b9844SJames Wright } 563*472b9844SJames Wright 564*472b9844SJames Wright PetscCall(DMSetUp(*dm)); 565*472b9844SJames Wright 566*472b9844SJames Wright PetscCall(DMCreateLabel(*dm, "zone")); 567*472b9844SJames Wright if (rank == 0) { 568*472b9844SJames Wright int z, c, c_loc, v_loc; 569*472b9844SJames Wright 570*472b9844SJames Wright PetscCall(DMGetLabel(*dm, "zone", &label)); 571*472b9844SJames Wright for (z = 1, c = 0; z <= nzones; ++z) { 572*472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType; 573*472b9844SJames Wright cgsize_t elementDataSize, *elements, start, end; 574*472b9844SJames Wright int nbndry, parentFlag; 575*472b9844SJames Wright PetscInt *cone, numc, numCorners, maxCorners = 27, pOrder; 576*472b9844SJames Wright const int S = 1; // Only support single section 577*472b9844SJames Wright 578*472b9844SJames Wright PetscCallCGNS(cg_section_read(cgid, B, z, S, buffer, &cellType, &start, &end, &nbndry, &parentFlag)); 579*472b9844SJames Wright numc = end - start; 580*472b9844SJames Wright PetscCallCGNS(cg_ElementDataSize(cgid, B, z, S, &elementDataSize)); 581*472b9844SJames Wright PetscCall(PetscMalloc2(elementDataSize, &elements, maxCorners, &cone)); 582*472b9844SJames Wright PetscCallCGNS(cg_poly_elements_read(cgid, B, z, S, elements, NULL, NULL)); 583*472b9844SJames Wright if (cellType == CGNS_ENUMV(MIXED)) { 584*472b9844SJames Wright /* CGNS uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */ 585*472b9844SJames Wright for (c_loc = 0, v = 0; c_loc <= numc; ++c_loc, ++c) { 586*472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(elements[v], NULL, &numCorners, NULL)); 587*472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(elements[v], NULL, &pOrder)); 588*472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder); 589*472b9844SJames Wright ++v; 590*472b9844SJames Wright for (v_loc = 0; v_loc < numCorners; ++v_loc, ++v) cone[v_loc] = elements[v] + numCells - 1; 591*472b9844SJames Wright PetscCall(DMPlexReorderCell(*dm, c, cone)); 592*472b9844SJames Wright PetscCall(DMPlexSetCone(*dm, c, cone)); 593*472b9844SJames Wright PetscCall(DMLabelSetValue(label, c, z)); 594*472b9844SJames Wright } 595*472b9844SJames Wright } else { 596*472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, NULL, &numCorners, NULL)); 597*472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, NULL, &pOrder)); 598*472b9844SJames Wright PetscCheck(pOrder == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Serial CGNS reader only supports first order elements, not %" PetscInt_FMT " order", pOrder); 599*472b9844SJames Wright /* CGNS uses Fortran-based indexing, DMPlex uses C-style and numbers cell first then vertices. */ 600*472b9844SJames Wright for (c_loc = 0, v = 0; c_loc <= numc; ++c_loc, ++c) { 601*472b9844SJames Wright for (v_loc = 0; v_loc < numCorners; ++v_loc, ++v) cone[v_loc] = elements[v] + numCells - 1; 602*472b9844SJames Wright PetscCall(DMPlexReorderCell(*dm, c, cone)); 603*472b9844SJames Wright PetscCall(DMPlexSetCone(*dm, c, cone)); 604*472b9844SJames Wright PetscCall(DMLabelSetValue(label, c, z)); 605*472b9844SJames Wright } 606*472b9844SJames Wright } 607*472b9844SJames Wright PetscCall(PetscFree2(elements, cone)); 608*472b9844SJames Wright } 609*472b9844SJames Wright } 610*472b9844SJames Wright 611*472b9844SJames Wright PetscCall(DMPlexSymmetrize(*dm)); 612*472b9844SJames Wright PetscCall(DMPlexStratify(*dm)); 613*472b9844SJames Wright if (interpolate) { 614*472b9844SJames Wright DM idm; 615*472b9844SJames Wright 616*472b9844SJames Wright PetscCall(DMPlexInterpolate(*dm, &idm)); 617*472b9844SJames Wright PetscCall(DMDestroy(dm)); 618*472b9844SJames Wright *dm = idm; 619*472b9844SJames Wright } 620*472b9844SJames Wright 621*472b9844SJames Wright /* Read coordinates */ 622*472b9844SJames Wright PetscCall(DMSetCoordinateDim(*dm, coordDim)); 623*472b9844SJames Wright PetscCall(DMGetCoordinateDM(*dm, &cdm)); 624*472b9844SJames Wright PetscCall(DMGetLocalSection(cdm, &coordSection)); 625*472b9844SJames Wright PetscCall(PetscSectionSetNumFields(coordSection, 1)); 626*472b9844SJames Wright PetscCall(PetscSectionSetFieldComponents(coordSection, 0, coordDim)); 627*472b9844SJames Wright PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices)); 628*472b9844SJames Wright for (v = numCells; v < numCells + numVertices; ++v) { 629*472b9844SJames Wright PetscCall(PetscSectionSetDof(coordSection, v, dim)); 630*472b9844SJames Wright PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, coordDim)); 631*472b9844SJames Wright } 632*472b9844SJames Wright PetscCall(PetscSectionSetUp(coordSection)); 633*472b9844SJames Wright 634*472b9844SJames Wright PetscCall(DMCreateLocalVector(cdm, &coordinates)); 635*472b9844SJames Wright PetscCall(VecGetArray(coordinates, &coords)); 636*472b9844SJames Wright if (rank == 0) { 637*472b9844SJames Wright PetscInt off = 0; 638*472b9844SJames Wright float *x[3]; 639*472b9844SJames Wright int z, d; 640*472b9844SJames Wright 641*472b9844SJames Wright PetscCall(PetscMalloc3(numVertices, &x[0], numVertices, &x[1], numVertices, &x[2])); 642*472b9844SJames Wright for (z = 1; z <= nzones; ++z) { 643*472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype; 644*472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */ 645*472b9844SJames Wright cgsize_t range_min[3] = {1, 1, 1}; 646*472b9844SJames Wright cgsize_t range_max[3] = {1, 1, 1}; 647*472b9844SJames Wright int ngrids, ncoords; 648*472b9844SJames Wright 649*472b9844SJames Wright PetscCallCGNS(cg_zone_read(cgid, B, z, buffer, sizes)); 650*472b9844SJames Wright range_max[0] = sizes[0]; 651*472b9844SJames Wright PetscCallCGNS(cg_ngrids(cgid, B, z, &ngrids)); 652*472b9844SJames Wright PetscCheck(ngrids <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single grid, not %d", ngrids); 653*472b9844SJames Wright PetscCallCGNS(cg_ncoords(cgid, B, z, &ncoords)); 654*472b9844SJames Wright PetscCheck(ncoords == coordDim, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a coordinate array for each dimension, not %d", ncoords); 655*472b9844SJames Wright for (d = 0; d < coordDim; ++d) { 656*472b9844SJames Wright PetscCallCGNS(cg_coord_info(cgid, B, z, 1 + d, &datatype, buffer)); 657*472b9844SJames Wright PetscCallCGNS(cg_coord_read(cgid, B, z, buffer, CGNS_ENUMV(RealSingle), range_min, range_max, x[d])); 658*472b9844SJames Wright } 659*472b9844SJames Wright if (coordDim >= 1) { 660*472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 0] = x[0][v]; 661*472b9844SJames Wright } 662*472b9844SJames Wright if (coordDim >= 2) { 663*472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 1] = x[1][v]; 664*472b9844SJames Wright } 665*472b9844SJames Wright if (coordDim >= 3) { 666*472b9844SJames Wright for (v = 0; v < sizes[0]; ++v) coords[(v + off) * coordDim + 2] = x[2][v]; 667*472b9844SJames Wright } 668*472b9844SJames Wright off += sizes[0]; 669*472b9844SJames Wright } 670*472b9844SJames Wright PetscCall(PetscFree3(x[0], x[1], x[2])); 671*472b9844SJames Wright } 672*472b9844SJames Wright PetscCall(VecRestoreArray(coordinates, &coords)); 673*472b9844SJames Wright 674*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 675*472b9844SJames Wright PetscCall(VecSetBlockSize(coordinates, coordDim)); 676*472b9844SJames Wright PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 677*472b9844SJames Wright PetscCall(VecDestroy(&coordinates)); 678*472b9844SJames Wright 679*472b9844SJames Wright /* Read boundary conditions */ 680*472b9844SJames Wright PetscCall(DMGetNumLabels(*dm, &labelIdRange[0])); 681*472b9844SJames Wright if (rank == 0) { 682*472b9844SJames Wright CGNS_ENUMT(BCType_t) bctype; 683*472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype; 684*472b9844SJames Wright CGNS_ENUMT(PointSetType_t) pointtype; 685*472b9844SJames Wright cgsize_t *points; 686*472b9844SJames Wright PetscReal *normals; 687*472b9844SJames Wright int normal[3]; 688*472b9844SJames Wright char *bcname = buffer; 689*472b9844SJames Wright cgsize_t npoints, nnormals; 690*472b9844SJames Wright int z, nbc, bc, c, ndatasets; 691*472b9844SJames Wright 692*472b9844SJames Wright for (z = 1; z <= nzones; ++z) { 693*472b9844SJames Wright PetscCallCGNS(cg_nbocos(cgid, B, z, &nbc)); 694*472b9844SJames Wright for (bc = 1; bc <= nbc; ++bc) { 695*472b9844SJames Wright PetscCallCGNS(cg_boco_info(cgid, B, z, bc, bcname, &bctype, &pointtype, &npoints, normal, &nnormals, &datatype, &ndatasets)); 696*472b9844SJames Wright PetscCall(DMCreateLabel(*dm, bcname)); 697*472b9844SJames Wright PetscCall(DMGetLabel(*dm, bcname, &label)); 698*472b9844SJames Wright PetscCall(PetscMalloc2(npoints, &points, nnormals, &normals)); 699*472b9844SJames Wright PetscCallCGNS(cg_boco_read(cgid, B, z, bc, points, (void *)normals)); 700*472b9844SJames Wright if (pointtype == CGNS_ENUMV(ElementRange)) { 701*472b9844SJames Wright // Range of cells: assuming half-open interval 702*472b9844SJames Wright for (c = points[0]; c < points[1]; ++c) PetscCall(DMLabelSetValue(label, c - cellStart[z - 1], 1)); 703*472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(ElementList)) { 704*472b9844SJames Wright // List of cells 705*472b9844SJames Wright for (c = 0; c < npoints; ++c) PetscCall(DMLabelSetValue(label, points[c] - cellStart[z - 1], 1)); 706*472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(PointRange)) { 707*472b9844SJames Wright CGNS_ENUMT(GridLocation_t) gridloc; 708*472b9844SJames Wright 709*472b9844SJames Wright // List of points: 710*472b9844SJames Wright PetscCallCGNS(cg_goto(cgid, 1, "Zone_t", z, "BC_t", bc, "end")); 711*472b9844SJames Wright PetscCallCGNS(cg_gridlocation_read(&gridloc)); 712*472b9844SJames Wright // Range of points: assuming half-open interval 713*472b9844SJames Wright for (c = points[0]; c < points[1]; ++c) { 714*472b9844SJames Wright if (gridloc == CGNS_ENUMV(Vertex)) PetscCall(DMLabelSetValue(label, c - vertStart[z - 1], 1)); 715*472b9844SJames Wright else PetscCall(DMLabelSetValue(label, c - cellStart[z - 1], 1)); 716*472b9844SJames Wright } 717*472b9844SJames Wright } else if (pointtype == CGNS_ENUMV(PointList)) { 718*472b9844SJames Wright CGNS_ENUMT(GridLocation_t) gridloc; 719*472b9844SJames Wright 720*472b9844SJames Wright // List of points: 721*472b9844SJames Wright PetscCallCGNS(cg_goto(cgid, 1, "Zone_t", z, "BC_t", bc, "end")); 722*472b9844SJames Wright PetscCallCGNS(cg_gridlocation_read(&gridloc)); 723*472b9844SJames Wright for (c = 0; c < npoints; ++c) { 724*472b9844SJames Wright if (gridloc == CGNS_ENUMV(Vertex)) PetscCall(DMLabelSetValue(label, points[c] - vertStart[z - 1], 1)); 725*472b9844SJames Wright else PetscCall(DMLabelSetValue(label, points[c] - cellStart[z - 1], 1)); 726*472b9844SJames Wright } 727*472b9844SJames Wright } else SETERRQ(comm, PETSC_ERR_SUP, "Unsupported point set type %d", (int)pointtype); 728*472b9844SJames Wright PetscCall(PetscFree2(points, normals)); 729*472b9844SJames Wright } 730*472b9844SJames Wright } 731*472b9844SJames Wright PetscCall(PetscFree2(cellStart, vertStart)); 732*472b9844SJames Wright } 733*472b9844SJames Wright PetscCall(DMGetNumLabels(*dm, &labelIdRange[1])); 734*472b9844SJames Wright PetscCallMPI(MPI_Bcast(labelIdRange, 2, MPIU_INT, 0, comm)); 735*472b9844SJames Wright 736*472b9844SJames Wright /* Create BC labels at all processes */ 737*472b9844SJames Wright for (labelId = labelIdRange[0]; labelId < labelIdRange[1]; ++labelId) { 738*472b9844SJames Wright char *labelName = buffer; 739*472b9844SJames Wright size_t len = sizeof(buffer); 740*472b9844SJames Wright const char *locName; 741*472b9844SJames Wright 742*472b9844SJames Wright if (rank == 0) { 743*472b9844SJames Wright PetscCall(DMGetLabelByNum(*dm, labelId, &label)); 744*472b9844SJames Wright PetscCall(PetscObjectGetName((PetscObject)label, &locName)); 745*472b9844SJames Wright PetscCall(PetscStrncpy(labelName, locName, len)); 746*472b9844SJames Wright } 747*472b9844SJames Wright PetscCallMPI(MPI_Bcast(labelName, (PetscMPIInt)len, MPIU_INT, 0, comm)); 748*472b9844SJames Wright PetscCallMPI(DMCreateLabel(*dm, labelName)); 749*472b9844SJames Wright } 750*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 751*472b9844SJames Wright } 752*472b9844SJames Wright 753*472b9844SJames Wright PetscErrorCode DMPlexCreateCGNS_Internal_Parallel(MPI_Comm comm, PetscInt cgid, PetscBool interpolate, DM *dm) 754*472b9844SJames Wright { 755*472b9844SJames Wright PetscMPIInt num_proc, rank; 756*472b9844SJames Wright /* Read from file */ 757*472b9844SJames Wright char basename[CGIO_MAX_NAME_LENGTH + 1]; 758*472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1]; 759*472b9844SJames Wright int dim = 0, physDim = 0, coordDim = 0; 760*472b9844SJames Wright PetscInt NVertices = 0, NCells = 0; 761*472b9844SJames Wright int nzones = 0, nbases; 762*472b9844SJames Wright int z = 1; // Only supports single zone files 763*472b9844SJames Wright int B = 1; // Only supports single base 764*472b9844SJames Wright 765*472b9844SJames Wright PetscFunctionBegin; 766*472b9844SJames Wright PetscCallMPI(MPI_Comm_rank(comm, &rank)); 767*472b9844SJames Wright PetscCallMPI(MPI_Comm_size(comm, &num_proc)); 768*472b9844SJames Wright PetscCall(DMCreate(comm, dm)); 769*472b9844SJames Wright PetscCall(DMSetType(*dm, DMPLEX)); 770*472b9844SJames Wright 771*472b9844SJames Wright PetscCallCGNS(cg_nbases(cgid, &nbases)); 772*472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases); 773*472b9844SJames Wright // From the CGNS web page cell_dim phys_dim (embedding space in PETSC) CGNS defines as length of spatial vectors/components) 774*472b9844SJames Wright PetscCallCGNS(cg_base_read(cgid, B, basename, &dim, &physDim)); 775*472b9844SJames Wright PetscCallCGNS(cg_nzones(cgid, B, &nzones)); 776*472b9844SJames Wright PetscCheck(nzones == 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Parallel reader limited to one zone, not %d", nzones); 777*472b9844SJames Wright { 778*472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */ 779*472b9844SJames Wright 780*472b9844SJames Wright PetscCallCGNS(cg_zone_read(cgid, B, z, buffer, sizes)); 781*472b9844SJames Wright NVertices = sizes[0]; 782*472b9844SJames Wright NCells = sizes[1]; 783*472b9844SJames Wright } 784*472b9844SJames Wright 785*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)*dm, basename)); 786*472b9844SJames Wright PetscCall(DMSetDimension(*dm, dim)); 787*472b9844SJames Wright coordDim = dim; 788*472b9844SJames Wright 789*472b9844SJames 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 790*472b9844SJames Wright // call to get this right but continuing for now with single section, single topology, one zone. 791*472b9844SJames Wright // establish element ranges for my rank 792*472b9844SJames Wright PetscInt mystarte, myende, mystartv, myendv, myownede, myownedv; 793*472b9844SJames Wright PetscLayout elem_map, vtx_map; 794*472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NCells, 1, &elem_map)); 795*472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NVertices, 1, &vtx_map)); 796*472b9844SJames Wright PetscCall(PetscLayoutGetRange(elem_map, &mystarte, &myende)); 797*472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(elem_map, &myownede)); 798*472b9844SJames Wright PetscCall(PetscLayoutGetRange(vtx_map, &mystartv, &myendv)); 799*472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(vtx_map, &myownedv)); 800*472b9844SJames Wright 801*472b9844SJames Wright // -- Build Plex in parallel 802*472b9844SJames Wright DMPolytopeType dm_cell_type; 803*472b9844SJames Wright PetscInt pOrder = 1, numClosure = -1; 804*472b9844SJames Wright cgsize_t *elements; 805*472b9844SJames Wright { 806*472b9844SJames Wright int nsections; 807*472b9844SJames Wright PetscInt *elementsQ1, numCorners = -1; 808*472b9844SJames Wright const int *perm; 809*472b9844SJames Wright cgsize_t start, end; // Throwaway 810*472b9844SJames Wright 811*472b9844SJames Wright cg_nsections(cgid, B, z, &nsections); 812*472b9844SJames Wright // Read element connectivity 813*472b9844SJames Wright for (int index_sect = 1; index_sect <= nsections; index_sect++) { 814*472b9844SJames Wright int nbndry, parentFlag; 815*472b9844SJames Wright PetscInt cell_dim; 816*472b9844SJames Wright CGNS_ENUMT(ElementType_t) cellType; 817*472b9844SJames Wright 818*472b9844SJames Wright PetscCallCGNS(cg_section_read(cgid, B, z, index_sect, buffer, &cellType, &start, &end, &nbndry, &parentFlag)); 819*472b9844SJames Wright 820*472b9844SJames Wright PetscCall(CGNSElementTypeGetTopologyInfo(cellType, &dm_cell_type, &numCorners, &cell_dim)); 821*472b9844SJames Wright // Skip over element that are not max dimension (ie. boundary elements) 822*472b9844SJames Wright if (cell_dim != dim) continue; 823*472b9844SJames Wright PetscCall(CGNSElementTypeGetDiscretizationInfo(cellType, &numClosure, &pOrder)); 824*472b9844SJames Wright PetscCall(PetscMalloc1(myownede * numClosure, &elements)); 825*472b9844SJames Wright PetscCallCGNS(cgp_elements_read_data(cgid, B, z, index_sect, mystarte + 1, myende, elements)); 826*472b9844SJames Wright for (PetscInt v = 0; v < myownede * numClosure; ++v) elements[v] -= 1; // 0 based 827*472b9844SJames Wright break; 828*472b9844SJames Wright } 829*472b9844SJames Wright 830*472b9844SJames Wright // Create corners-only connectivity 831*472b9844SJames Wright PetscCall(PetscMalloc1(myownede * numCorners, &elementsQ1)); 832*472b9844SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numCorners, NULL, &perm)); 833*472b9844SJames Wright for (PetscInt e = 0; e < myownede; ++e) { 834*472b9844SJames Wright for (PetscInt v = 0; v < numCorners; ++v) elementsQ1[e * numCorners + perm[v]] = elements[e * numClosure + v]; 835*472b9844SJames Wright } 836*472b9844SJames Wright 837*472b9844SJames Wright // Build cell-vertex Plex 838*472b9844SJames Wright PetscCall(DMPlexBuildFromCellListParallel(*dm, myownede, myownedv, NVertices, numCorners, elementsQ1, NULL, NULL)); 839*472b9844SJames Wright PetscCall(DMViewFromOptions(*dm, NULL, "-corner_dm_view")); 840*472b9844SJames Wright PetscCall(PetscFree(elementsQ1)); 841*472b9844SJames Wright } 842*472b9844SJames Wright 843*472b9844SJames Wright if (interpolate) { 844*472b9844SJames Wright DM idm; 845*472b9844SJames Wright PetscCall(DMPlexInterpolate(*dm, &idm)); 846*472b9844SJames Wright PetscCall(DMDestroy(dm)); 847*472b9844SJames Wright *dm = idm; 848*472b9844SJames Wright PetscCall(DMViewFromOptions(*dm, NULL, "-interpolate_dm_view")); 849*472b9844SJames Wright } 850*472b9844SJames Wright 851*472b9844SJames Wright // -- Create SF for naive nodal-data read to elements 852*472b9844SJames Wright PetscSF plex_to_cgns_sf; 853*472b9844SJames Wright { 854*472b9844SJames Wright PetscInt nleaves, num_comp; 855*472b9844SJames Wright PetscInt *leaf, num_leaves = 0; 856*472b9844SJames Wright PetscInt cStart, cEnd; 857*472b9844SJames Wright const int *perm; 858*472b9844SJames Wright PetscSF cgns_to_local_sf; 859*472b9844SJames Wright PetscSection local_section; 860*472b9844SJames Wright PetscFE fe; 861*472b9844SJames Wright 862*472b9844SJames Wright // sfNatural requires PetscSection to handle DMDistribute, so we use PetscFE to define the section 863*472b9844SJames Wright // Use number of components = 1 to work with just the nodes themselves 864*472b9844SJames Wright PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, dm_cell_type, pOrder, PETSC_DETERMINE, &fe)); 865*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)fe, "FE for sfNatural")); 866*472b9844SJames Wright PetscCall(DMAddField(*dm, NULL, (PetscObject)fe)); 867*472b9844SJames Wright PetscCall(DMCreateDS(*dm)); 868*472b9844SJames Wright PetscCall(PetscFEDestroy(&fe)); 869*472b9844SJames Wright 870*472b9844SJames Wright PetscCall(DMGetLocalSection(*dm, &local_section)); 871*472b9844SJames Wright PetscCall(PetscSectionViewFromOptions(local_section, NULL, "-fe_natural_section_view")); 872*472b9844SJames Wright PetscCall(PetscSectionGetFieldComponents(local_section, 0, &num_comp)); 873*472b9844SJames Wright PetscCall(PetscSectionGetStorageSize(local_section, &nleaves)); 874*472b9844SJames Wright nleaves /= num_comp; 875*472b9844SJames Wright PetscCall(PetscMalloc1(nleaves, &leaf)); 876*472b9844SJames Wright for (PetscInt i = 0; i < nleaves; i++) leaf[i] = -1; 877*472b9844SJames Wright 878*472b9844SJames Wright // Get the permutation from CGNS closure numbering to PLEX closure numbering 879*472b9844SJames Wright PetscCall(DMPlexCGNSGetPermutation_Internal(dm_cell_type, numClosure, NULL, &perm)); 880*472b9844SJames Wright PetscCall(DMPlexGetHeightStratum(*dm, 0, &cStart, &cEnd)); 881*472b9844SJames Wright for (PetscInt cell = cStart; cell < cEnd; ++cell) { 882*472b9844SJames Wright PetscInt num_closure_dof, *closure_idx = NULL; 883*472b9844SJames Wright 884*472b9844SJames Wright PetscCall(DMPlexGetClosureIndices(*dm, local_section, local_section, cell, PETSC_FALSE, &num_closure_dof, &closure_idx, NULL, NULL)); 885*472b9844SJames Wright PetscAssert(numClosure * num_comp == num_closure_dof, comm, PETSC_ERR_PLIB, "Closure dof size does not match polytope"); 886*472b9844SJames Wright for (PetscInt i = 0; i < numClosure; i++) { 887*472b9844SJames Wright PetscInt li = closure_idx[perm[i] * num_comp] / num_comp; 888*472b9844SJames Wright if (li < 0) continue; 889*472b9844SJames Wright 890*472b9844SJames Wright PetscInt cgns_idx = elements[cell * numClosure + i]; 891*472b9844SJames Wright if (leaf[li] == -1) { 892*472b9844SJames Wright leaf[li] = cgns_idx; 893*472b9844SJames Wright num_leaves++; 894*472b9844SJames Wright } else PetscAssert(leaf[li] == cgns_idx, PETSC_COMM_SELF, PETSC_ERR_PLIB, "leaf does not match previously set"); 895*472b9844SJames Wright } 896*472b9844SJames Wright PetscCall(DMPlexRestoreClosureIndices(*dm, local_section, local_section, cell, PETSC_FALSE, &num_closure_dof, &closure_idx, NULL, NULL)); 897*472b9844SJames Wright } 898*472b9844SJames Wright PetscAssert(num_leaves == nleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "leaf count in closure does not match nleaves"); 899*472b9844SJames Wright PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)*dm), &cgns_to_local_sf)); 900*472b9844SJames Wright PetscCall(PetscSFSetGraphLayout(cgns_to_local_sf, vtx_map, nleaves, NULL, PETSC_USE_POINTER, leaf)); 901*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)cgns_to_local_sf, "CGNS to Plex SF")); 902*472b9844SJames Wright PetscCall(PetscSFViewFromOptions(cgns_to_local_sf, NULL, "-CGNStoPlex_sf_view")); 903*472b9844SJames Wright PetscCall(PetscFree(leaf)); 904*472b9844SJames Wright PetscCall(PetscFree(elements)); 905*472b9844SJames Wright 906*472b9844SJames Wright { // Convert cgns_to_local to global_to_cgns 907*472b9844SJames Wright PetscSF sectionsf, cgns_to_global_sf; 908*472b9844SJames Wright 909*472b9844SJames Wright PetscCall(DMGetSectionSF(*dm, §ionsf)); 910*472b9844SJames Wright PetscCall(PetscSFComposeInverse(cgns_to_local_sf, sectionsf, &cgns_to_global_sf)); 911*472b9844SJames Wright PetscCall(PetscSFDestroy(&cgns_to_local_sf)); 912*472b9844SJames Wright PetscCall(PetscSFCreateInverseSF(cgns_to_global_sf, &plex_to_cgns_sf)); 913*472b9844SJames Wright PetscCall(PetscObjectSetName((PetscObject)plex_to_cgns_sf, "Global Plex to CGNS")); 914*472b9844SJames Wright PetscCall(PetscSFDestroy(&cgns_to_global_sf)); 915*472b9844SJames Wright } 916*472b9844SJames Wright } 917*472b9844SJames Wright 918*472b9844SJames Wright { // -- Set coordinates for DM 919*472b9844SJames Wright PetscScalar *coords; 920*472b9844SJames Wright float *x[3]; 921*472b9844SJames Wright double *xd[3]; 922*472b9844SJames Wright PetscBool read_with_double; 923*472b9844SJames Wright PetscFE cfe; 924*472b9844SJames Wright 925*472b9844SJames Wright // Setup coordinate space first. Use pOrder here for isoparametric; revisit with CPEX-0045 High Order. 926*472b9844SJames Wright PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, coordDim, dm_cell_type, pOrder, PETSC_DETERMINE, &cfe)); 927*472b9844SJames Wright PetscCall(DMSetCoordinateDisc(*dm, cfe, PETSC_FALSE)); 928*472b9844SJames Wright PetscCall(PetscFEDestroy(&cfe)); 929*472b9844SJames Wright 930*472b9844SJames Wright { // Determine if coords are written in single or double precision 931*472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype; 932*472b9844SJames Wright 933*472b9844SJames Wright PetscCallCGNS(cg_coord_info(cgid, B, z, 1, &datatype, buffer)); 934*472b9844SJames Wright if (datatype == CGNS_ENUMV(RealDouble)) read_with_double = PETSC_TRUE; 935*472b9844SJames Wright else read_with_double = PETSC_TRUE; 936*472b9844SJames Wright } 937*472b9844SJames Wright 938*472b9844SJames Wright // Read coords from file and set into component-major ordering 939*472b9844SJames Wright if (read_with_double) PetscCall(PetscMalloc3(myownedv, &xd[0], myownedv, &xd[1], myownedv, &xd[2])); 940*472b9844SJames Wright else PetscCall(PetscMalloc3(myownedv, &x[0], myownedv, &x[1], myownedv, &x[2])); 941*472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * coordDim, &coords)); 942*472b9844SJames Wright { 943*472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */ 944*472b9844SJames Wright cgsize_t range_min[3] = {mystartv + 1, 1, 1}; 945*472b9844SJames Wright cgsize_t range_max[3] = {myendv, 1, 1}; 946*472b9844SJames Wright int ngrids, ncoords; 947*472b9844SJames Wright 948*472b9844SJames Wright PetscCallCGNS(cg_zone_read(cgid, B, z, buffer, sizes)); 949*472b9844SJames Wright PetscCallCGNS(cg_ngrids(cgid, B, z, &ngrids)); 950*472b9844SJames Wright PetscCheck(ngrids <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single grid, not %d", ngrids); 951*472b9844SJames Wright PetscCallCGNS(cg_ncoords(cgid, B, z, &ncoords)); 952*472b9844SJames Wright PetscCheck(ncoords == coordDim, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a coordinate array for each dimension, not %d", ncoords); 953*472b9844SJames Wright if (read_with_double) { 954*472b9844SJames Wright for (int d = 0; d < coordDim; ++d) PetscCallCGNS(cgp_coord_read_data(cgid, B, z, (d + 1), range_min, range_max, xd[d])); 955*472b9844SJames Wright if (coordDim >= 1) { 956*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 0] = xd[0][v]; 957*472b9844SJames Wright } 958*472b9844SJames Wright if (coordDim >= 2) { 959*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 1] = xd[1][v]; 960*472b9844SJames Wright } 961*472b9844SJames Wright if (coordDim >= 3) { 962*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 2] = xd[2][v]; 963*472b9844SJames Wright } 964*472b9844SJames Wright } else { 965*472b9844SJames Wright for (int d = 0; d < coordDim; ++d) PetscCallCGNS(cgp_coord_read_data(cgid, 1, z, (d + 1), range_min, range_max, x[d])); 966*472b9844SJames Wright if (coordDim >= 1) { 967*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 0] = x[0][v]; 968*472b9844SJames Wright } 969*472b9844SJames Wright if (coordDim >= 2) { 970*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 1] = x[1][v]; 971*472b9844SJames Wright } 972*472b9844SJames Wright if (coordDim >= 3) { 973*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) coords[v * coordDim + 2] = x[2][v]; 974*472b9844SJames Wright } 975*472b9844SJames Wright } 976*472b9844SJames Wright } 977*472b9844SJames Wright if (read_with_double) PetscCall(PetscFree3(xd[0], xd[1], xd[2])); 978*472b9844SJames Wright else PetscCall(PetscFree3(x[0], x[1], x[2])); 979*472b9844SJames Wright 980*472b9844SJames Wright { // Reduce CGNS-ordered coordinate nodes to Plex ordering, and set DM's coordinates 981*472b9844SJames Wright Vec coord_global; 982*472b9844SJames Wright MPI_Datatype unit; 983*472b9844SJames Wright PetscScalar *coord_global_array; 984*472b9844SJames Wright DM cdm; 985*472b9844SJames Wright 986*472b9844SJames Wright PetscCall(DMGetCoordinateDM(*dm, &cdm)); 987*472b9844SJames Wright PetscCall(DMCreateGlobalVector(cdm, &coord_global)); 988*472b9844SJames Wright PetscCall(VecGetArrayWrite(coord_global, &coord_global_array)); 989*472b9844SJames Wright PetscCallMPI(MPI_Type_contiguous(coordDim, MPIU_SCALAR, &unit)); 990*472b9844SJames Wright PetscCallMPI(MPI_Type_commit(&unit)); 991*472b9844SJames Wright PetscCall(PetscSFReduceBegin(plex_to_cgns_sf, unit, coords, coord_global_array, MPI_REPLACE)); 992*472b9844SJames Wright PetscCall(PetscSFReduceEnd(plex_to_cgns_sf, unit, coords, coord_global_array, MPI_REPLACE)); 993*472b9844SJames Wright PetscCall(VecRestoreArrayWrite(coord_global, &coord_global_array)); 994*472b9844SJames Wright PetscCallMPI(MPI_Type_free(&unit)); 995*472b9844SJames Wright PetscCall(DMSetCoordinates(*dm, coord_global)); 996*472b9844SJames Wright PetscCall(VecDestroy(&coord_global)); 997*472b9844SJames Wright } 998*472b9844SJames Wright PetscCall(PetscFree(coords)); 999*472b9844SJames Wright } 1000*472b9844SJames Wright 1001*472b9844SJames Wright // -- Set sfNatural for solution vectors in CGNS file 1002*472b9844SJames Wright // NOTE: We set sfNatural to be the map between the original CGNS ordering of nodes and the Plex ordering of nodes. 1003*472b9844SJames Wright PetscCall(PetscSFViewFromOptions(plex_to_cgns_sf, NULL, "-sfNatural_init_view")); 1004*472b9844SJames Wright PetscCall(DMSetNaturalSF(*dm, plex_to_cgns_sf)); 1005*472b9844SJames Wright PetscCall(DMSetUseNatural(*dm, PETSC_TRUE)); 1006*472b9844SJames Wright PetscCall(PetscSFDestroy(&plex_to_cgns_sf)); 1007*472b9844SJames Wright 1008*472b9844SJames Wright PetscCall(PetscLayoutDestroy(&elem_map)); 1009*472b9844SJames Wright PetscCall(PetscLayoutDestroy(&vtx_map)); 10103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10115f34f2dcSJed Brown } 10125f34f2dcSJed Brown 10135f34f2dcSJed Brown // node_l2g must be freed 1014d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateNodeNumbering(DM dm, PetscInt *num_local_nodes, PetscInt *num_global_nodes, PetscInt *nStart, PetscInt *nEnd, const PetscInt **node_l2g) 1015d71ae5a4SJacob Faibussowitsch { 10165f34f2dcSJed Brown PetscSection local_section; 10175f34f2dcSJed Brown PetscSF point_sf; 10185f34f2dcSJed Brown PetscInt pStart, pEnd, spStart, spEnd, *points, nleaves, ncomp, *nodes; 10195f34f2dcSJed Brown PetscMPIInt comm_size; 10205f34f2dcSJed Brown const PetscInt *ilocal, field = 0; 10215f34f2dcSJed Brown 10225f34f2dcSJed Brown PetscFunctionBegin; 10235f34f2dcSJed Brown *num_local_nodes = -1; 10245f34f2dcSJed Brown *num_global_nodes = -1; 10255f34f2dcSJed Brown *nStart = -1; 10265f34f2dcSJed Brown *nEnd = -1; 10275f34f2dcSJed Brown *node_l2g = NULL; 10285f34f2dcSJed Brown 10295f34f2dcSJed Brown PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &comm_size)); 10305f34f2dcSJed Brown PetscCall(DMGetLocalSection(dm, &local_section)); 10315f34f2dcSJed Brown PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 10325f34f2dcSJed Brown PetscCall(PetscSectionGetChart(local_section, &spStart, &spEnd)); 10335f34f2dcSJed Brown PetscCall(DMGetPointSF(dm, &point_sf)); 10345f34f2dcSJed Brown if (comm_size == 1) nleaves = 0; 10355f34f2dcSJed Brown else PetscCall(PetscSFGetGraph(point_sf, NULL, &nleaves, &ilocal, NULL)); 10365f34f2dcSJed Brown PetscCall(PetscSectionGetFieldComponents(local_section, field, &ncomp)); 10375f34f2dcSJed Brown 10385f34f2dcSJed Brown PetscInt local_node = 0, owned_node = 0, owned_start = 0; 10395f34f2dcSJed Brown for (PetscInt p = spStart, leaf = 0; p < spEnd; p++) { 10405f34f2dcSJed Brown PetscInt dof; 10415f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof)); 10425f34f2dcSJed 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); 10435f34f2dcSJed Brown local_node += dof / ncomp; 10445f34f2dcSJed Brown if (leaf < nleaves && p == ilocal[leaf]) { // skip points owned by a different process 10455f34f2dcSJed Brown leaf++; 10465f34f2dcSJed Brown } else { 10475f34f2dcSJed Brown owned_node += dof / ncomp; 10485f34f2dcSJed Brown } 10495f34f2dcSJed Brown } 10505f34f2dcSJed Brown PetscCallMPI(MPI_Exscan(&owned_node, &owned_start, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 10515f34f2dcSJed Brown PetscCall(PetscMalloc1(pEnd - pStart, &points)); 10525f34f2dcSJed Brown owned_node = 0; 10535f34f2dcSJed Brown for (PetscInt p = spStart, leaf = 0; p < spEnd; p++) { 10545f34f2dcSJed Brown if (leaf < nleaves && p == ilocal[leaf]) { // skip points owned by a different process 10555f34f2dcSJed Brown points[p - pStart] = -1; 10565f34f2dcSJed Brown leaf++; 10575f34f2dcSJed Brown continue; 10585f34f2dcSJed Brown } 10595f34f2dcSJed Brown PetscInt dof, offset; 10605f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof)); 10615f34f2dcSJed Brown PetscCall(PetscSectionGetFieldOffset(local_section, p, field, &offset)); 10625f34f2dcSJed 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); 10635f34f2dcSJed Brown points[p - pStart] = owned_start + owned_node; 10645f34f2dcSJed Brown owned_node += dof / ncomp; 10655f34f2dcSJed Brown } 10665f34f2dcSJed Brown if (comm_size > 1) { 10675f34f2dcSJed Brown PetscCall(PetscSFBcastBegin(point_sf, MPIU_INT, points, points, MPI_REPLACE)); 10685f34f2dcSJed Brown PetscCall(PetscSFBcastEnd(point_sf, MPIU_INT, points, points, MPI_REPLACE)); 10695f34f2dcSJed Brown } 10705f34f2dcSJed Brown 10715f34f2dcSJed Brown // Set up global indices for each local node 10725f34f2dcSJed Brown PetscCall(PetscMalloc1(local_node, &nodes)); 10735f34f2dcSJed Brown for (PetscInt p = spStart; p < spEnd; p++) { 10745f34f2dcSJed Brown PetscInt dof, offset; 10755f34f2dcSJed Brown PetscCall(PetscSectionGetFieldDof(local_section, p, field, &dof)); 10765f34f2dcSJed Brown PetscCall(PetscSectionGetFieldOffset(local_section, p, field, &offset)); 10775f34f2dcSJed Brown for (PetscInt n = 0; n < dof / ncomp; n++) nodes[offset / ncomp + n] = points[p - pStart] + n; 10785f34f2dcSJed Brown } 10795f34f2dcSJed Brown PetscCall(PetscFree(points)); 10805f34f2dcSJed Brown *num_local_nodes = local_node; 10815f34f2dcSJed Brown *nStart = owned_start; 10825f34f2dcSJed Brown *nEnd = owned_start + owned_node; 1083712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(&owned_node, num_global_nodes, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 10845f34f2dcSJed Brown *node_l2g = nodes; 10853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10865f34f2dcSJed Brown } 10875f34f2dcSJed Brown 1088d71ae5a4SJacob Faibussowitsch PetscErrorCode DMView_PlexCGNS(DM dm, PetscViewer viewer) 1089d71ae5a4SJacob Faibussowitsch { 10905f34f2dcSJed Brown PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data; 109144698e90SJames Wright PetscInt fvGhostStart; 10925f34f2dcSJed Brown PetscInt topo_dim, coord_dim, num_global_elems; 10935f34f2dcSJed Brown PetscInt cStart, cEnd, num_local_nodes, num_global_nodes, nStart, nEnd; 10945f34f2dcSJed Brown const PetscInt *node_l2g; 10955f34f2dcSJed Brown Vec coord; 1096b85bf5edSJed Brown DM colloc_dm, cdm; 10975f34f2dcSJed Brown PetscMPIInt size; 10985f34f2dcSJed Brown const char *dm_name; 10995f34f2dcSJed Brown int base, zone; 11005f34f2dcSJed Brown cgsize_t isize[3]; 11015f34f2dcSJed Brown 11025f34f2dcSJed Brown PetscFunctionBegin; 110325760affSJed Brown if (!cgv->file_num) { 110425760affSJed Brown PetscInt time_step; 110525760affSJed Brown PetscCall(DMGetOutputSequenceNumber(dm, &time_step, NULL)); 110625760affSJed Brown PetscCall(PetscViewerCGNSFileOpen_Internal(viewer, time_step)); 110725760affSJed Brown } 11085f34f2dcSJed Brown PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 11095f34f2dcSJed Brown PetscCall(DMGetDimension(dm, &topo_dim)); 11105f34f2dcSJed Brown PetscCall(DMGetCoordinateDim(dm, &coord_dim)); 11115f34f2dcSJed Brown PetscCall(PetscObjectGetName((PetscObject)dm, &dm_name)); 11125f34f2dcSJed Brown PetscCallCGNS(cg_base_write(cgv->file_num, dm_name, topo_dim, coord_dim, &base)); 11135f34f2dcSJed Brown PetscCallCGNS(cg_goto(cgv->file_num, base, NULL)); 11145f34f2dcSJed Brown PetscCallCGNS(cg_dataclass_write(CGNS_ENUMV(NormalizedByDimensional))); 11155f34f2dcSJed Brown 1116b85bf5edSJed Brown { 1117b85bf5edSJed Brown PetscFE fe, fe_coord; 11189bb8f83bSJed Brown PetscClassId ds_id; 1119b85bf5edSJed Brown PetscDualSpace dual_space, dual_space_coord; 11202d1fc720SJed Brown PetscInt num_fields, field_order = -1, field_order_coord; 1121b85bf5edSJed Brown PetscBool is_simplex; 11225b8b2c14SJed Brown PetscCall(DMGetNumFields(dm, &num_fields)); 11239bb8f83bSJed Brown if (num_fields > 0) { 11249bb8f83bSJed Brown PetscCall(DMGetField(dm, 0, NULL, (PetscObject *)&fe)); 11259bb8f83bSJed Brown PetscCall(PetscObjectGetClassId((PetscObject)fe, &ds_id)); 11262d1fc720SJed Brown if (ds_id != PETSCFE_CLASSID) { 11272d1fc720SJed Brown fe = NULL; 11282d1fc720SJed Brown if (ds_id == PETSCFV_CLASSID) field_order = -1; // use whatever is present for coords; field will be CellCenter 11292d1fc720SJed Brown else field_order = 1; // assume vertex-based linear elements 11302d1fc720SJed Brown } 11319bb8f83bSJed Brown } else fe = NULL; 1132b85bf5edSJed Brown if (fe) { 1133b85bf5edSJed Brown PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 1134b85bf5edSJed Brown PetscCall(PetscDualSpaceGetOrder(dual_space, &field_order)); 11352d1fc720SJed Brown } 11365f34f2dcSJed Brown PetscCall(DMGetCoordinateDM(dm, &cdm)); 1137b85bf5edSJed Brown PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe_coord)); 11389bb8f83bSJed Brown { 11399bb8f83bSJed Brown PetscClassId id; 11409bb8f83bSJed Brown PetscCall(PetscObjectGetClassId((PetscObject)fe_coord, &id)); 11419bb8f83bSJed Brown if (id != PETSCFE_CLASSID) fe_coord = NULL; 11429bb8f83bSJed Brown } 1143b85bf5edSJed Brown if (fe_coord) { 1144b85bf5edSJed Brown PetscCall(PetscFEGetDualSpace(fe_coord, &dual_space_coord)); 1145b85bf5edSJed Brown PetscCall(PetscDualSpaceGetOrder(dual_space_coord, &field_order_coord)); 1146b85bf5edSJed Brown } else field_order_coord = 1; 11472d1fc720SJed Brown if (field_order > 0 && field_order != field_order_coord) { 1148b85bf5edSJed Brown PetscInt quadrature_order = field_order; 1149b85bf5edSJed Brown PetscCall(DMClone(dm, &colloc_dm)); 11507d4eb7abSJed Brown { // Inform the new colloc_dm that it is a coordinate DM so isoperiodic affine corrections can be applied 11511fca310dSJames Wright const PetscSF *face_sfs; 11521fca310dSJames Wright PetscInt num_face_sfs; 11531fca310dSJames Wright PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs)); 11541fca310dSJames Wright PetscCall(DMPlexSetIsoperiodicFaceSF(colloc_dm, num_face_sfs, (PetscSF *)face_sfs)); 11551fca310dSJames Wright if (face_sfs) colloc_dm->periodic.setup = DMPeriodicCoordinateSetUp_Internal; 11567d4eb7abSJed Brown } 1157b85bf5edSJed Brown PetscCall(DMPlexIsSimplex(dm, &is_simplex)); 1158b85bf5edSJed Brown PetscCall(PetscFECreateLagrange(PetscObjectComm((PetscObject)dm), topo_dim, coord_dim, is_simplex, field_order, quadrature_order, &fe)); 1159e44f6aebSMatthew G. Knepley PetscCall(DMSetCoordinateDisc(colloc_dm, fe, PETSC_TRUE)); 1160b85bf5edSJed Brown PetscCall(PetscFEDestroy(&fe)); 1161b85bf5edSJed Brown } else { 1162b85bf5edSJed Brown PetscCall(PetscObjectReference((PetscObject)dm)); 1163b85bf5edSJed Brown colloc_dm = dm; 1164b85bf5edSJed Brown } 1165b85bf5edSJed Brown } 1166b85bf5edSJed Brown PetscCall(DMGetCoordinateDM(colloc_dm, &cdm)); 11675f34f2dcSJed Brown PetscCall(DMPlexCreateNodeNumbering(cdm, &num_local_nodes, &num_global_nodes, &nStart, &nEnd, &node_l2g)); 1168b85bf5edSJed Brown PetscCall(DMGetCoordinatesLocal(colloc_dm, &coord)); 11695f34f2dcSJed Brown PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 117044698e90SJames Wright PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &fvGhostStart, NULL)); 117144698e90SJames Wright if (fvGhostStart >= 0) cEnd = fvGhostStart; 11725f34f2dcSJed Brown num_global_elems = cEnd - cStart; 1173712fec58SPierre Jolivet PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &num_global_elems, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 11745f34f2dcSJed Brown isize[0] = num_global_nodes; 11755f34f2dcSJed Brown isize[1] = num_global_elems; 11765f34f2dcSJed Brown isize[2] = 0; 11775f34f2dcSJed Brown PetscCallCGNS(cg_zone_write(cgv->file_num, base, "Zone", isize, CGNS_ENUMV(Unstructured), &zone)); 11785f34f2dcSJed Brown 11795f34f2dcSJed Brown { 11805f34f2dcSJed Brown const PetscScalar *X; 11815f34f2dcSJed Brown PetscScalar *x; 11825f34f2dcSJed Brown int coord_ids[3]; 11835f34f2dcSJed Brown 11845f34f2dcSJed Brown PetscCall(VecGetArrayRead(coord, &X)); 11855f34f2dcSJed Brown for (PetscInt d = 0; d < coord_dim; d++) { 11865f34f2dcSJed Brown const double exponents[] = {0, 1, 0, 0, 0}; 11875f34f2dcSJed Brown char coord_name[64]; 11885f34f2dcSJed Brown PetscCall(PetscSNPrintf(coord_name, sizeof coord_name, "Coordinate%c", 'X' + (int)d)); 11895f34f2dcSJed Brown PetscCallCGNS(cgp_coord_write(cgv->file_num, base, zone, CGNS_ENUMV(RealDouble), coord_name, &coord_ids[d])); 11905f34f2dcSJed Brown PetscCallCGNS(cg_goto(cgv->file_num, base, "Zone_t", zone, "GridCoordinates", 0, coord_name, 0, NULL)); 11915f34f2dcSJed Brown PetscCallCGNS(cg_exponents_write(CGNS_ENUMV(RealDouble), exponents)); 11925f34f2dcSJed Brown } 11935f34f2dcSJed Brown 11945f34f2dcSJed Brown int section; 11955f34f2dcSJed Brown cgsize_t e_owned, e_global, e_start, *conn = NULL; 11965f34f2dcSJed Brown const int *perm; 1197e853fb4cSJames Wright CGNS_ENUMT(ElementType_t) element_type = CGNS_ENUMV(ElementTypeNull); 11985f34f2dcSJed Brown { 11995f34f2dcSJed Brown PetscCall(PetscMalloc1(nEnd - nStart, &x)); 12005f34f2dcSJed Brown for (PetscInt d = 0; d < coord_dim; d++) { 12015f34f2dcSJed Brown for (PetscInt n = 0; n < num_local_nodes; n++) { 12025f34f2dcSJed Brown PetscInt gn = node_l2g[n]; 12035f34f2dcSJed Brown if (gn < nStart || nEnd <= gn) continue; 12045f34f2dcSJed Brown x[gn - nStart] = X[n * coord_dim + d]; 12055f34f2dcSJed Brown } 12065f34f2dcSJed Brown // CGNS nodes use 1-based indexing 12075f34f2dcSJed Brown cgsize_t start = nStart + 1, end = nEnd; 12085f34f2dcSJed Brown PetscCallCGNS(cgp_coord_write_data(cgv->file_num, base, zone, coord_ids[d], &start, &end, x)); 12095f34f2dcSJed Brown } 12105f34f2dcSJed Brown PetscCall(PetscFree(x)); 12115f34f2dcSJed Brown PetscCall(VecRestoreArrayRead(coord, &X)); 12125f34f2dcSJed Brown } 12135f34f2dcSJed Brown 121459191b1eSJames Wright e_owned = cEnd - cStart; 121544698e90SJames Wright if (e_owned > 0) { 121644698e90SJames Wright DMPolytopeType cell_type; 121744698e90SJames Wright 121844698e90SJames Wright PetscCall(DMPlexGetCellType(dm, cStart, &cell_type)); 12195f34f2dcSJed Brown for (PetscInt i = cStart, c = 0; i < cEnd; i++) { 12205f34f2dcSJed Brown PetscInt closure_dof, *closure_indices, elem_size; 122144698e90SJames Wright 12225f34f2dcSJed Brown PetscCall(DMPlexGetClosureIndices(cdm, cdm->localSection, cdm->localSection, i, PETSC_FALSE, &closure_dof, &closure_indices, NULL, NULL)); 12235f34f2dcSJed Brown elem_size = closure_dof / coord_dim; 122444698e90SJames Wright if (!conn) PetscCall(PetscMalloc1(e_owned * elem_size, &conn)); 12255f34f2dcSJed Brown PetscCall(DMPlexCGNSGetPermutation_Internal(cell_type, closure_dof / coord_dim, &element_type, &perm)); 1226ad540459SPierre Jolivet for (PetscInt j = 0; j < elem_size; j++) conn[c++] = node_l2g[closure_indices[perm[j] * coord_dim] / coord_dim] + 1; 12275f34f2dcSJed Brown PetscCall(DMPlexRestoreClosureIndices(cdm, cdm->localSection, cdm->localSection, i, PETSC_FALSE, &closure_dof, &closure_indices, NULL, NULL)); 12285f34f2dcSJed Brown } 122944698e90SJames Wright } 123044698e90SJames Wright 123159191b1eSJames Wright { // Get global element_type (for ranks that do not have owned elements) 123259191b1eSJames Wright PetscInt local_element_type, global_element_type; 123359191b1eSJames Wright 123459191b1eSJames Wright local_element_type = e_owned > 0 ? element_type : -1; 123559191b1eSJames Wright PetscCall(MPIU_Allreduce(&local_element_type, &global_element_type, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)viewer))); 123659191b1eSJames Wright if (local_element_type != -1) PetscCheck(local_element_type == global_element_type, PETSC_COMM_SELF, PETSC_ERR_SUP, "Ranks with different element types not supported"); 123759191b1eSJames Wright element_type = global_element_type; 123859191b1eSJames Wright } 12391fb9530eSJeongu Kim PetscCall(MPIU_Allreduce(&e_owned, &e_global, 1, MPIU_CGSIZE, MPI_SUM, PetscObjectComm((PetscObject)dm))); 12401fb9530eSJeongu 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); 12415f34f2dcSJed Brown e_start = 0; 12421fb9530eSJeongu Kim PetscCallMPI(MPI_Exscan(&e_owned, &e_start, 1, MPIU_CGSIZE, MPI_SUM, PetscObjectComm((PetscObject)dm))); 12435f34f2dcSJed Brown PetscCallCGNS(cgp_section_write(cgv->file_num, base, zone, "Elem", element_type, 1, e_global, 0, §ion)); 12445f34f2dcSJed Brown PetscCallCGNS(cgp_elements_write_data(cgv->file_num, base, zone, section, e_start + 1, e_start + e_owned, conn)); 12455f34f2dcSJed Brown PetscCall(PetscFree(conn)); 12465f34f2dcSJed Brown 12475f34f2dcSJed Brown cgv->base = base; 12485f34f2dcSJed Brown cgv->zone = zone; 12495f34f2dcSJed Brown cgv->node_l2g = node_l2g; 12505f34f2dcSJed Brown cgv->num_local_nodes = num_local_nodes; 12515f34f2dcSJed Brown cgv->nStart = nStart; 12525f34f2dcSJed Brown cgv->nEnd = nEnd; 12539bb8f83bSJed Brown cgv->eStart = e_start; 12549bb8f83bSJed Brown cgv->eEnd = e_start + e_owned; 12555f34f2dcSJed Brown if (1) { 12565f34f2dcSJed Brown PetscMPIInt rank; 12575f34f2dcSJed Brown int *efield; 12585f34f2dcSJed Brown int sol, field; 12595f34f2dcSJed Brown DMLabel label; 12605f34f2dcSJed Brown PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 12615f34f2dcSJed Brown PetscCall(PetscMalloc1(e_owned, &efield)); 12625f34f2dcSJed Brown for (PetscInt i = 0; i < e_owned; i++) efield[i] = rank; 12635f34f2dcSJed Brown PetscCallCGNS(cg_sol_write(cgv->file_num, base, zone, "CellInfo", CGNS_ENUMV(CellCenter), &sol)); 12645f34f2dcSJed Brown PetscCallCGNS(cgp_field_write(cgv->file_num, base, zone, sol, CGNS_ENUMV(Integer), "Rank", &field)); 12655f34f2dcSJed Brown cgsize_t start = e_start + 1, end = e_start + e_owned; 12665f34f2dcSJed Brown PetscCallCGNS(cgp_field_write_data(cgv->file_num, base, zone, sol, field, &start, &end, efield)); 12675f34f2dcSJed Brown PetscCall(DMGetLabel(dm, "Cell Sets", &label)); 12685f34f2dcSJed Brown if (label) { 12695f34f2dcSJed Brown for (PetscInt c = cStart; c < cEnd; c++) { 12705f34f2dcSJed Brown PetscInt value; 12715f34f2dcSJed Brown PetscCall(DMLabelGetValue(label, c, &value)); 12725f34f2dcSJed Brown efield[c - cStart] = value; 12735f34f2dcSJed Brown } 12745f34f2dcSJed Brown PetscCallCGNS(cgp_field_write(cgv->file_num, base, zone, sol, CGNS_ENUMV(Integer), "CellSet", &field)); 12755f34f2dcSJed Brown PetscCallCGNS(cgp_field_write_data(cgv->file_num, base, zone, sol, field, &start, &end, efield)); 12765f34f2dcSJed Brown } 12775f34f2dcSJed Brown PetscCall(PetscFree(efield)); 12785f34f2dcSJed Brown } 12795f34f2dcSJed Brown } 1280b85bf5edSJed Brown PetscCall(DMDestroy(&colloc_dm)); 12813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12825f34f2dcSJed Brown } 12835f34f2dcSJed Brown 1284d71ae5a4SJacob Faibussowitsch PetscErrorCode VecView_Plex_Local_CGNS(Vec V, PetscViewer viewer) 1285d71ae5a4SJacob Faibussowitsch { 12865f34f2dcSJed Brown PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data; 12875f34f2dcSJed Brown DM dm; 12885f34f2dcSJed Brown PetscSection section; 128944698e90SJames Wright PetscInt time_step, num_fields, pStart, pEnd, fvGhostStart; 12905f34f2dcSJed Brown PetscReal time, *time_slot; 12919812b6beSJed Brown size_t *step_slot; 12925f34f2dcSJed Brown const PetscScalar *v; 12935f34f2dcSJed Brown char solution_name[PETSC_MAX_PATH_LEN]; 12945f34f2dcSJed Brown int sol; 12955f34f2dcSJed Brown 12965f34f2dcSJed Brown PetscFunctionBegin; 12975f34f2dcSJed Brown PetscCall(VecGetDM(V, &dm)); 1298ec2db9e4SJames Wright PetscCall(DMGetLocalSection(dm, §ion)); 1299ec2db9e4SJames Wright PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 130044698e90SJames Wright PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &fvGhostStart, NULL)); 130144698e90SJames Wright if (fvGhostStart >= 0) pEnd = fvGhostStart; 1302ec2db9e4SJames Wright 13035f34f2dcSJed Brown if (!cgv->node_l2g) PetscCall(DMView(dm, viewer)); 1304ec2db9e4SJames Wright if (!cgv->grid_loc) { // Determine if writing to cell-centers or to nodes 1305ec2db9e4SJames Wright PetscInt cStart, cEnd; 1306ec2db9e4SJames Wright PetscInt local_grid_loc, global_grid_loc; 1307ec2db9e4SJames Wright 1308ec2db9e4SJames Wright PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 130944698e90SJames Wright if (fvGhostStart >= 0) cEnd = fvGhostStart; 1310ec2db9e4SJames Wright if (cgv->num_local_nodes == 0) local_grid_loc = -1; 1311ec2db9e4SJames Wright else if (cStart == pStart && cEnd == pEnd) local_grid_loc = CGNS_ENUMV(CellCenter); 1312ec2db9e4SJames Wright else local_grid_loc = CGNS_ENUMV(Vertex); 1313ec2db9e4SJames Wright 1314ec2db9e4SJames Wright PetscCall(MPIU_Allreduce(&local_grid_loc, &global_grid_loc, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)viewer))); 1315ec2db9e4SJames Wright if (local_grid_loc != -1) 1316ec2db9e4SJames 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); 1317ec2db9e4SJames 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); 1318ec2db9e4SJames Wright cgv->grid_loc = global_grid_loc; 1319ec2db9e4SJames Wright } 1320ec2db9e4SJames Wright if (!cgv->nodal_field) { 1321ec2db9e4SJames Wright switch (cgv->grid_loc) { 1322ec2db9e4SJames Wright case CGNS_ENUMV(Vertex): { 1323ec2db9e4SJames Wright PetscCall(PetscMalloc1(cgv->nEnd - cgv->nStart, &cgv->nodal_field)); 1324ec2db9e4SJames Wright } break; 1325ec2db9e4SJames Wright case CGNS_ENUMV(CellCenter): { 1326ec2db9e4SJames Wright PetscCall(PetscMalloc1(cgv->eEnd - cgv->eStart, &cgv->nodal_field)); 1327ec2db9e4SJames Wright } break; 1328ec2db9e4SJames Wright default: 1329ec2db9e4SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only write for Vertex and CellCenter grid locations"); 1330ec2db9e4SJames Wright } 1331ec2db9e4SJames Wright } 13325f34f2dcSJed Brown if (!cgv->output_times) PetscCall(PetscSegBufferCreate(sizeof(PetscReal), 20, &cgv->output_times)); 13339812b6beSJed Brown if (!cgv->output_steps) PetscCall(PetscSegBufferCreate(sizeof(size_t), 20, &cgv->output_steps)); 13345f34f2dcSJed Brown 13355f34f2dcSJed Brown PetscCall(DMGetOutputSequenceNumber(dm, &time_step, &time)); 13369371c9d4SSatish Balay if (time_step < 0) { 13379371c9d4SSatish Balay time_step = 0; 13389371c9d4SSatish Balay time = 0.; 13399371c9d4SSatish Balay } 13405f34f2dcSJed Brown PetscCall(PetscSegBufferGet(cgv->output_times, 1, &time_slot)); 13415f34f2dcSJed Brown *time_slot = time; 13429812b6beSJed Brown PetscCall(PetscSegBufferGet(cgv->output_steps, 1, &step_slot)); 13439812b6beSJed Brown *step_slot = time_step; 13445f34f2dcSJed Brown PetscCall(PetscSNPrintf(solution_name, sizeof solution_name, "FlowSolution%" PetscInt_FMT, time_step)); 1345ec2db9e4SJames Wright PetscCallCGNS(cg_sol_write(cgv->file_num, cgv->base, cgv->zone, solution_name, cgv->grid_loc, &sol)); 13465f34f2dcSJed Brown PetscCall(VecGetArrayRead(V, &v)); 134700a86070SJed Brown PetscCall(PetscSectionGetNumFields(section, &num_fields)); 134800a86070SJed Brown for (PetscInt field = 0; field < num_fields; field++) { 134900a86070SJed Brown PetscInt ncomp; 13509bb8f83bSJed Brown const char *field_name; 13519bb8f83bSJed Brown PetscCall(PetscSectionGetFieldName(section, field, &field_name)); 135200a86070SJed Brown PetscCall(PetscSectionGetFieldComponents(section, field, &ncomp)); 13535f34f2dcSJed Brown for (PetscInt comp = 0; comp < ncomp; comp++) { 13545f34f2dcSJed Brown int cgfield; 13555f34f2dcSJed Brown const char *comp_name; 13569bb8f83bSJed Brown char cgns_field_name[32]; // CGNS max field name is 32 13575f34f2dcSJed Brown CGNS_ENUMT(DataType_t) datatype; 13585f34f2dcSJed Brown PetscCall(PetscSectionGetComponentName(section, field, comp, &comp_name)); 135944698e90SJames 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)); 13609bb8f83bSJed Brown else if (field_name[0] == '\0') PetscCall(PetscStrncpy(cgns_field_name, comp_name, sizeof cgns_field_name)); 13619bb8f83bSJed Brown else PetscCall(PetscSNPrintf(cgns_field_name, sizeof cgns_field_name, "%s.%s", field_name, comp_name)); 13625f34f2dcSJed Brown PetscCall(PetscCGNSDataType(PETSC_SCALAR, &datatype)); 13639bb8f83bSJed Brown PetscCallCGNS(cgp_field_write(cgv->file_num, cgv->base, cgv->zone, sol, datatype, cgns_field_name, &cgfield)); 136400a86070SJed Brown for (PetscInt p = pStart, n = 0; p < pEnd; p++) { 136500a86070SJed Brown PetscInt off, dof; 136600a86070SJed Brown PetscCall(PetscSectionGetFieldDof(section, p, field, &dof)); 136700a86070SJed Brown if (dof == 0) continue; 136800a86070SJed Brown PetscCall(PetscSectionGetFieldOffset(section, p, field, &off)); 136900a86070SJed Brown for (PetscInt c = comp; c < dof; c += ncomp, n++) { 1370ec2db9e4SJames Wright switch (cgv->grid_loc) { 13719bb8f83bSJed Brown case CGNS_ENUMV(Vertex): { 13725f34f2dcSJed Brown PetscInt gn = cgv->node_l2g[n]; 13735f34f2dcSJed Brown if (gn < cgv->nStart || cgv->nEnd <= gn) continue; 137400a86070SJed Brown cgv->nodal_field[gn - cgv->nStart] = v[off + c]; 13759bb8f83bSJed Brown } break; 13769bb8f83bSJed Brown case CGNS_ENUMV(CellCenter): { 13779bb8f83bSJed Brown cgv->nodal_field[n] = v[off + c]; 13789bb8f83bSJed Brown } break; 13799bb8f83bSJed Brown default: 13809bb8f83bSJed Brown SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only pack for Vertex and CellCenter grid locations"); 13819bb8f83bSJed Brown } 138200a86070SJed Brown } 13835f34f2dcSJed Brown } 13845f34f2dcSJed Brown // CGNS nodes use 1-based indexing 1385ec2db9e4SJames Wright cgsize_t start, end; 1386ec2db9e4SJames Wright switch (cgv->grid_loc) { 1387ec2db9e4SJames Wright case CGNS_ENUMV(Vertex): { 1388ec2db9e4SJames Wright start = cgv->nStart + 1; 1389ec2db9e4SJames Wright end = cgv->nEnd; 1390ec2db9e4SJames Wright } break; 1391ec2db9e4SJames Wright case CGNS_ENUMV(CellCenter): { 13929bb8f83bSJed Brown start = cgv->eStart + 1; 13939bb8f83bSJed Brown end = cgv->eEnd; 1394ec2db9e4SJames Wright } break; 1395ec2db9e4SJames Wright default: 1396ec2db9e4SJames Wright SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only write for Vertex and CellCenter grid locations"); 13979bb8f83bSJed Brown } 13985f34f2dcSJed Brown PetscCallCGNS(cgp_field_write_data(cgv->file_num, cgv->base, cgv->zone, sol, cgfield, &start, &end, cgv->nodal_field)); 13995f34f2dcSJed Brown } 140000a86070SJed Brown } 14015f34f2dcSJed Brown PetscCall(VecRestoreArrayRead(V, &v)); 140225760affSJed Brown PetscCall(PetscViewerCGNSCheckBatch_Internal(viewer)); 14033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 14045f34f2dcSJed Brown } 1405*472b9844SJames Wright 1406*472b9844SJames Wright PetscErrorCode VecLoad_Plex_CGNS_Internal(Vec V, PetscViewer viewer) 1407*472b9844SJames Wright { 1408*472b9844SJames Wright MPI_Comm comm; 1409*472b9844SJames Wright char buffer[CGIO_MAX_NAME_LENGTH + 1]; 1410*472b9844SJames Wright PetscViewer_CGNS *cgv = (PetscViewer_CGNS *)viewer->data; 1411*472b9844SJames Wright int cgid = cgv->file_num; 1412*472b9844SJames Wright PetscBool use_parallel_viewer = PETSC_FALSE; 1413*472b9844SJames Wright int z = 1; // Only support one zone 1414*472b9844SJames Wright int B = 1; // Only support one base 1415*472b9844SJames Wright int numComp; 1416*472b9844SJames Wright PetscInt V_numComps, mystartv, myendv, myownedv; 1417*472b9844SJames Wright 1418*472b9844SJames Wright PetscFunctionBeginUser; 1419*472b9844SJames Wright PetscCall(PetscObjectGetComm((PetscObject)V, &comm)); 1420*472b9844SJames Wright 1421*472b9844SJames Wright PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_cgns_parallel", &use_parallel_viewer, NULL)); 1422*472b9844SJames 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"); 1423*472b9844SJames Wright 1424*472b9844SJames Wright { // Get CGNS node ownership information 1425*472b9844SJames Wright int nbases, nzones; 1426*472b9844SJames Wright PetscInt NVertices; 1427*472b9844SJames Wright PetscLayout vtx_map; 1428*472b9844SJames Wright cgsize_t sizes[3]; /* Number of vertices, number of cells, number of boundary vertices */ 1429*472b9844SJames Wright 1430*472b9844SJames Wright PetscCallCGNS(cg_nbases(cgid, &nbases)); 1431*472b9844SJames Wright PetscCheck(nbases <= 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "CGNS file must have a single base, not %d", nbases); 1432*472b9844SJames Wright PetscCallCGNS(cg_nzones(cgid, B, &nzones)); 1433*472b9844SJames Wright PetscCheck(nzones == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "limited to one zone %d", (int)nzones); 1434*472b9844SJames Wright 1435*472b9844SJames Wright PetscCallCGNS(cg_zone_read(cgid, B, z, buffer, sizes)); 1436*472b9844SJames Wright NVertices = sizes[0]; 1437*472b9844SJames Wright 1438*472b9844SJames Wright PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, NVertices, 1, &vtx_map)); 1439*472b9844SJames Wright PetscCall(PetscLayoutGetRange(vtx_map, &mystartv, &myendv)); 1440*472b9844SJames Wright PetscCall(PetscLayoutGetLocalSize(vtx_map, &myownedv)); 1441*472b9844SJames Wright PetscCall(PetscLayoutDestroy(&vtx_map)); 1442*472b9844SJames Wright } 1443*472b9844SJames Wright 1444*472b9844SJames Wright { // -- Read data from file into Vec 1445*472b9844SJames Wright PetscScalar *fields = NULL; 1446*472b9844SJames Wright PetscSF sfNatural; 1447*472b9844SJames Wright 1448*472b9844SJames Wright { // Check compatibility between sfNatural and the data source and sink 1449*472b9844SJames Wright DM dm; 1450*472b9844SJames Wright PetscInt nleaves, nroots, V_local_size; 1451*472b9844SJames Wright 1452*472b9844SJames Wright PetscCall(VecGetDM(V, &dm)); 1453*472b9844SJames Wright PetscCall(DMGetNaturalSF(dm, &sfNatural)); 1454*472b9844SJames Wright PetscCheck(sfNatural, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM of Vec must have sfNatural"); 1455*472b9844SJames Wright PetscCall(PetscSFGetGraph(sfNatural, &nroots, &nleaves, NULL, NULL)); 1456*472b9844SJames Wright PetscCall(VecGetLocalSize(V, &V_local_size)); 1457*472b9844SJames 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); 1458*472b9844SJames 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); 1459*472b9844SJames Wright V_numComps = V_local_size / nroots; 1460*472b9844SJames Wright } 1461*472b9844SJames Wright 1462*472b9844SJames Wright { // Read data into component-major ordering 1463*472b9844SJames Wright int isol, numSols; 1464*472b9844SJames Wright CGNS_ENUMT(DataType_t) datatype; 1465*472b9844SJames Wright double *fields_CGNS; 1466*472b9844SJames Wright 1467*472b9844SJames Wright PetscCallCGNS(cg_nsols(cgid, B, z, &numSols)); 1468*472b9844SJames Wright PetscCall(PetscViewerCGNSGetSolutionFileIndex_Internal(viewer, &isol)); 1469*472b9844SJames Wright PetscCallCGNS(cg_nfields(cgid, B, z, isol, &numComp)); 1470*472b9844SJames Wright PetscCheck(V_numComps == numComp, 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); 1471*472b9844SJames Wright 1472*472b9844SJames Wright cgsize_t range_min[3] = {mystartv + 1, 1, 1}; 1473*472b9844SJames Wright cgsize_t range_max[3] = {myendv, 1, 1}; 1474*472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * numComp, &fields_CGNS)); 1475*472b9844SJames Wright PetscCall(PetscMalloc1(myownedv * numComp, &fields)); 1476*472b9844SJames Wright for (int d = 0; d < numComp; ++d) { 1477*472b9844SJames Wright PetscCallCGNS(cg_field_info(cgid, B, z, isol, (d + 1), &datatype, buffer)); 1478*472b9844SJames Wright PetscCheck(datatype == CGNS_ENUMV(RealDouble), PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMETYPE, "Field %s in file is not of type double", buffer); 1479*472b9844SJames Wright PetscCallCGNS(cgp_field_read_data(cgid, B, z, isol, (d + 1), range_min, range_max, &fields_CGNS[d * myownedv])); 1480*472b9844SJames Wright } 1481*472b9844SJames Wright for (int d = 0; d < numComp; ++d) { 1482*472b9844SJames Wright for (PetscInt v = 0; v < myownedv; ++v) fields[v * numComp + d] = fields_CGNS[d * myownedv + v]; 1483*472b9844SJames Wright } 1484*472b9844SJames Wright PetscCall(PetscFree(fields_CGNS)); 1485*472b9844SJames Wright } 1486*472b9844SJames Wright 1487*472b9844SJames Wright { // Reduce fields into Vec array 1488*472b9844SJames Wright PetscScalar *V_array; 1489*472b9844SJames Wright MPI_Datatype fieldtype; 1490*472b9844SJames Wright 1491*472b9844SJames Wright PetscCall(VecGetArrayWrite(V, &V_array)); 1492*472b9844SJames Wright PetscCallMPI(MPI_Type_contiguous(numComp, MPIU_SCALAR, &fieldtype)); 1493*472b9844SJames Wright PetscCallMPI(MPI_Type_commit(&fieldtype)); 1494*472b9844SJames Wright PetscCall(PetscSFReduceBegin(sfNatural, fieldtype, fields, V_array, MPI_REPLACE)); 1495*472b9844SJames Wright PetscCall(PetscSFReduceEnd(sfNatural, fieldtype, fields, V_array, MPI_REPLACE)); 1496*472b9844SJames Wright PetscCallMPI(MPI_Type_free(&fieldtype)); 1497*472b9844SJames Wright PetscCall(VecRestoreArrayWrite(V, &V_array)); 1498*472b9844SJames Wright } 1499*472b9844SJames Wright PetscCall(PetscFree(fields)); 1500*472b9844SJames Wright } 1501*472b9844SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 1502*472b9844SJames Wright } 1503