xref: /petsc/src/dm/impls/plex/plexcreate.c (revision 44a422c483602b283b0a190c03c8ac5a4329df99)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
2cc4c1da9SBarry Smith #include <petsc/private/hashseti.h>
30c312b8eSJed Brown #include <petscsf.h>
4cc4c1da9SBarry Smith #include <petscdmplextransform.h> /*I   "petscdmplextransform.h"   I*/
59f6c5813SMatthew G. Knepley #include <petscdmlabelephemeral.h>
6b7f5c055SJed Brown #include <petsc/private/kernels/blockmatmult.h>
7b7f5c055SJed Brown #include <petsc/private/kernels/blockinvert.h>
8552f7358SJed Brown 
9d0812dedSMatthew G. Knepley #ifdef PETSC_HAVE_UNISTD_H
10d0812dedSMatthew G. Knepley   #include <unistd.h>
11d0812dedSMatthew G. Knepley #endif
12d0812dedSMatthew G. Knepley #include <errno.h>
13d0812dedSMatthew G. Knepley 
14708be2fdSJed Brown PetscLogEvent DMPLEX_CreateFromFile, DMPLEX_CreateFromOptions, DMPLEX_BuildFromCellList, DMPLEX_BuildCoordinatesFromCellList;
1558cd63d5SVaclav Hapla 
169318fe57SMatthew G. Knepley /* External function declarations here */
179318fe57SMatthew G. Knepley static PetscErrorCode DMInitialize_Plex(DM dm);
189318fe57SMatthew G. Knepley 
195552b385SBrandon PETSC_EXTERN PetscErrorCode DMPlexCheckEGADS_Private(DM dm)
205552b385SBrandon {
215552b385SBrandon   PetscObject modelObj;
225552b385SBrandon 
235552b385SBrandon   PetscFunctionBegin;
245552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dm, "EGADS Model", &modelObj));
255552b385SBrandon   PetscCheck(modelObj, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Input DM must have attached EGADS Geometry Model");
265552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
275552b385SBrandon }
285552b385SBrandon 
295552b385SBrandon static PetscErrorCode DMPlexCopyContext_Private(DM dmin, const char name[], DM dmout)
305552b385SBrandon {
315552b385SBrandon   PetscObject obj;
325552b385SBrandon 
335552b385SBrandon   PetscFunctionBegin;
345552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dmin, name, &obj));
355552b385SBrandon   if (obj) PetscCall(PetscObjectCompose((PetscObject)dmout, name, obj));
365552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
375552b385SBrandon }
385552b385SBrandon 
395552b385SBrandon static PetscErrorCode DMPlexSwapContext_Private(DM dmA, const char name[], DM dmB)
405552b385SBrandon {
415552b385SBrandon   PetscObject objA, objB;
425552b385SBrandon 
435552b385SBrandon   PetscFunctionBegin;
445552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dmA, name, &objA));
455552b385SBrandon   PetscCall(PetscObjectQuery((PetscObject)dmB, name, &objB));
465552b385SBrandon   PetscCall(PetscObjectReference(objA));
475552b385SBrandon   PetscCall(PetscObjectReference(objB));
485552b385SBrandon   PetscCall(PetscObjectCompose((PetscObject)dmA, name, objB));
495552b385SBrandon   PetscCall(PetscObjectCompose((PetscObject)dmB, name, objA));
505552b385SBrandon   PetscCall(PetscObjectDereference(objA));
515552b385SBrandon   PetscCall(PetscObjectDereference(objB));
525552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
535552b385SBrandon }
545552b385SBrandon 
555552b385SBrandon PetscErrorCode DMPlexCopyEGADSInfo_Internal(DM dmin, DM dmout)
565552b385SBrandon {
575552b385SBrandon   PetscFunctionBegin;
585552b385SBrandon   PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Model", dmout));
595552b385SBrandon   PetscCall(DMPlexCopyContext_Private(dmin, "EGADS Context", dmout));
605552b385SBrandon   PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Model", dmout));
615552b385SBrandon   PetscCall(DMPlexCopyContext_Private(dmin, "EGADSlite Context", dmout));
625552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
635552b385SBrandon }
645552b385SBrandon 
655552b385SBrandon static PetscErrorCode DMPlexSwapEGADSInfo_Private(DM dmA, DM dmB)
665552b385SBrandon {
675552b385SBrandon   PetscFunctionBegin;
685552b385SBrandon   PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Model", dmB));
695552b385SBrandon   PetscCall(DMPlexSwapContext_Private(dmA, "EGADS Context", dmB));
705552b385SBrandon   PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Model", dmB));
715552b385SBrandon   PetscCall(DMPlexSwapContext_Private(dmA, "EGADSlite Context", dmB));
725552b385SBrandon   PetscFunctionReturn(PETSC_SUCCESS);
735552b385SBrandon }
745552b385SBrandon 
75e600fa54SMatthew G. Knepley /* This copies internal things in the Plex structure that we generally want when making a new, related Plex */
76d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCopy_Internal(DM dmin, PetscBool copyPeriodicity, PetscBool copyOverlap, DM dmout)
77d71ae5a4SJacob Faibussowitsch {
784fb89dddSMatthew G. Knepley   const PetscReal     *maxCell, *Lstart, *L;
7912a88998SMatthew G. Knepley   VecType              vecType;
8012a88998SMatthew G. Knepley   MatType              matType;
81129f447cSJames Wright   PetscBool            dist, useCeed, balance_partition;
82adc21957SMatthew G. Knepley   DMReorderDefaultFlag reorder;
83e600fa54SMatthew G. Knepley 
84e600fa54SMatthew G. Knepley   PetscFunctionBegin;
85835f2295SStefano Zampini   if (dmin == dmout) PetscFunctionReturn(PETSC_SUCCESS);
8612a88998SMatthew G. Knepley   PetscCall(DMGetVecType(dmin, &vecType));
8712a88998SMatthew G. Knepley   PetscCall(DMSetVecType(dmout, vecType));
8812a88998SMatthew G. Knepley   PetscCall(DMGetMatType(dmin, &matType));
8912a88998SMatthew G. Knepley   PetscCall(DMSetMatType(dmout, matType));
90e600fa54SMatthew G. Knepley   if (copyPeriodicity) {
914fb89dddSMatthew G. Knepley     PetscCall(DMGetPeriodicity(dmin, &maxCell, &Lstart, &L));
924fb89dddSMatthew G. Knepley     PetscCall(DMSetPeriodicity(dmout, maxCell, Lstart, L));
933d0e8ed9SDavid Salac     PetscCall(DMLocalizeCoordinates(dmout));
94e600fa54SMatthew G. Knepley   }
959566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeGetDefault(dmin, &dist));
969566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeSetDefault(dmout, dist));
976bc1bd01Sksagiyam   PetscCall(DMPlexReorderGetDefault(dmin, &reorder));
986bc1bd01Sksagiyam   PetscCall(DMPlexReorderSetDefault(dmout, reorder));
995962854dSMatthew G. Knepley   PetscCall(DMPlexGetUseCeed(dmin, &useCeed));
1005962854dSMatthew G. Knepley   PetscCall(DMPlexSetUseCeed(dmout, useCeed));
101129f447cSJames Wright   PetscCall(DMPlexGetPartitionBalance(dmin, &balance_partition));
102129f447cSJames Wright   PetscCall(DMPlexSetPartitionBalance(dmout, balance_partition));
103e600fa54SMatthew G. Knepley   ((DM_Plex *)dmout->data)->useHashLocation = ((DM_Plex *)dmin->data)->useHashLocation;
1045962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printSetValues  = ((DM_Plex *)dmin->data)->printSetValues;
1055962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printFEM        = ((DM_Plex *)dmin->data)->printFEM;
1065962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printFVM        = ((DM_Plex *)dmin->data)->printFVM;
1075962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printL2         = ((DM_Plex *)dmin->data)->printL2;
1085962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printLocate     = ((DM_Plex *)dmin->data)->printLocate;
109a77a5016SMatthew G. Knepley   ((DM_Plex *)dmout->data)->printProject    = ((DM_Plex *)dmin->data)->printProject;
1105962854dSMatthew G. Knepley   ((DM_Plex *)dmout->data)->printTol        = ((DM_Plex *)dmin->data)->printTol;
1111baa6e33SBarry Smith   if (copyOverlap) PetscCall(DMPlexSetOverlap_Plex(dmout, dmin, 0));
1125552b385SBrandon   PetscCall(DMPlexCopyEGADSInfo_Internal(dmin, dmout));
1133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114e600fa54SMatthew G. Knepley }
115e600fa54SMatthew G. Knepley 
1169318fe57SMatthew G. Knepley /* Replace dm with the contents of ndm, and then destroy ndm
1179318fe57SMatthew G. Knepley    - Share the DM_Plex structure
1189318fe57SMatthew G. Knepley    - Share the coordinates
1199318fe57SMatthew G. Knepley    - Share the SF
1209318fe57SMatthew G. Knepley */
121d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexReplace_Internal(DM dm, DM *ndm)
122d71ae5a4SJacob Faibussowitsch {
1239318fe57SMatthew G. Knepley   PetscSF          sf;
1249318fe57SMatthew G. Knepley   DM               dmNew = *ndm, coordDM, coarseDM;
1259318fe57SMatthew G. Knepley   Vec              coords;
1262192575eSBarry Smith   PetscPointFn    *coordFunc;
1274fb89dddSMatthew G. Knepley   const PetscReal *maxCell, *Lstart, *L;
1289318fe57SMatthew G. Knepley   PetscInt         dim, cdim;
129e535cce4SJames Wright   PetscBool        use_natural;
1309318fe57SMatthew G. Knepley 
1319318fe57SMatthew G. Knepley   PetscFunctionBegin;
1329318fe57SMatthew G. Knepley   if (dm == dmNew) {
1339566063dSJacob Faibussowitsch     PetscCall(DMDestroy(ndm));
1343ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1359318fe57SMatthew G. Knepley   }
1369318fe57SMatthew G. Knepley   dm->setupcalled = dmNew->setupcalled;
137d0812dedSMatthew G. Knepley   if (!dm->hdr.name) {
138d0812dedSMatthew G. Knepley     const char *name;
139d0812dedSMatthew G. Knepley 
140d0812dedSMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)*ndm, &name));
141d0812dedSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)dm, name));
142d0812dedSMatthew G. Knepley   }
1433674be70SMatthew G. Knepley   {
1443674be70SMatthew G. Knepley     PetscInt ndim;
1453674be70SMatthew G. Knepley 
1463674be70SMatthew G. Knepley     // If topological dimensions are the same, we retain the old coordinate map,
1473674be70SMatthew G. Knepley     //   otherwise we overwrite with the new one
1483674be70SMatthew G. Knepley     PetscCall(DMGetDimension(dm, &dim));
1493674be70SMatthew G. Knepley     PetscCall(DMGetDimension(dmNew, &ndim));
1503674be70SMatthew G. Knepley     PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
1513674be70SMatthew G. Knepley     if (dim == ndim) PetscCall(DMPlexSetCoordinateMap(dmNew, coordFunc));
1523674be70SMatthew G. Knepley   }
1539566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmNew, &dim));
1549566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
1559566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmNew, &cdim));
1569566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, cdim));
1579566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dmNew, &sf));
1589566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(dm, sf));
1599566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dmNew, &coordDM));
1609566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dmNew, &coords));
1619566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDM(dm, coordDM));
1629566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coords));
1636858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dmNew, &coordDM));
1646858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dmNew, &coords));
1656858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(dm, coordDM));
1666858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(dm, coords));
1679318fe57SMatthew G. Knepley   /* Do not want to create the coordinate field if it does not already exist, so do not call DMGetCoordinateField() */
1686858538eSMatthew G. Knepley   PetscCall(DMFieldDestroy(&dm->coordinates[0].field));
1696858538eSMatthew G. Knepley   dm->coordinates[0].field = dmNew->coordinates[0].field;
1704fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dmNew, &maxCell, &Lstart, &L));
1714fb89dddSMatthew G. Knepley   PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
172e535cce4SJames Wright   PetscCall(DMGetNaturalSF(dmNew, &sf));
173e535cce4SJames Wright   PetscCall(DMSetNaturalSF(dm, sf));
174e535cce4SJames Wright   PetscCall(DMGetUseNatural(dmNew, &use_natural));
175e535cce4SJames Wright   PetscCall(DMSetUseNatural(dm, use_natural));
1769566063dSJacob Faibussowitsch   PetscCall(DMDestroy_Plex(dm));
1779566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Plex(dm));
1789318fe57SMatthew G. Knepley   dm->data = dmNew->data;
1799318fe57SMatthew G. Knepley   ((DM_Plex *)dmNew->data)->refct++;
1801fca310dSJames Wright   {
1811fca310dSJames Wright     PetscInt       num_face_sfs;
1821fca310dSJames Wright     const PetscSF *sfs;
1831fca310dSJames Wright     PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &sfs));
1841fca310dSJames Wright     PetscCall(DMPlexSetIsoperiodicFaceSF(dm, num_face_sfs, (PetscSF *)sfs)); // for the compose function effect on dm
1851fca310dSJames Wright   }
1869566063dSJacob Faibussowitsch   PetscCall(DMDestroyLabelLinkList_Internal(dm));
1879566063dSJacob Faibussowitsch   PetscCall(DMCopyLabels(dmNew, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
1889566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmNew, &coarseDM));
1899566063dSJacob Faibussowitsch   PetscCall(DMSetCoarseDM(dm, coarseDM));
1905552b385SBrandon   PetscCall(DMPlexCopyEGADSInfo_Internal(dmNew, dm));
1919566063dSJacob Faibussowitsch   PetscCall(DMDestroy(ndm));
1923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1939318fe57SMatthew G. Knepley }
1949318fe57SMatthew G. Knepley 
1959318fe57SMatthew G. Knepley /* Swap dm with the contents of dmNew
1969318fe57SMatthew G. Knepley    - Swap the DM_Plex structure
1979318fe57SMatthew G. Knepley    - Swap the coordinates
1989318fe57SMatthew G. Knepley    - Swap the point PetscSF
1999318fe57SMatthew G. Knepley */
200d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexSwap_Static(DM dmA, DM dmB)
201d71ae5a4SJacob Faibussowitsch {
2029318fe57SMatthew G. Knepley   DM          coordDMA, coordDMB;
2039318fe57SMatthew G. Knepley   Vec         coordsA, coordsB;
2049318fe57SMatthew G. Knepley   PetscSF     sfA, sfB;
2059318fe57SMatthew G. Knepley   DMField     fieldTmp;
2069318fe57SMatthew G. Knepley   void       *tmp;
2079318fe57SMatthew G. Knepley   DMLabelLink listTmp;
2089318fe57SMatthew G. Knepley   DMLabel     depthTmp;
2099318fe57SMatthew G. Knepley   PetscInt    tmpI;
2109318fe57SMatthew G. Knepley 
2119318fe57SMatthew G. Knepley   PetscFunctionBegin;
2123ba16761SJacob Faibussowitsch   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
2139566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dmA, &sfA));
2149566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dmB, &sfB));
2159566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)sfA));
2169566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(dmA, sfB));
2179566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(dmB, sfA));
2189566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)sfA));
2199318fe57SMatthew G. Knepley 
2209566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dmA, &coordDMA));
2219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dmB, &coordDMB));
2229566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)coordDMA));
2239566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDM(dmA, coordDMB));
2249566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDM(dmB, coordDMA));
2259566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
2269318fe57SMatthew G. Knepley 
2279566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dmA, &coordsA));
2289566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(dmB, &coordsB));
2299566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)coordsA));
2309566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmA, coordsB));
2319566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dmB, coordsA));
2329566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)coordsA));
2339318fe57SMatthew G. Knepley 
2346858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dmA, &coordDMA));
2356858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinateDM(dmB, &coordDMB));
2366858538eSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)coordDMA));
2376858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(dmA, coordDMB));
2386858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(dmB, coordDMA));
2396858538eSMatthew G. Knepley   PetscCall(PetscObjectDereference((PetscObject)coordDMA));
2406858538eSMatthew G. Knepley 
2416858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dmA, &coordsA));
2426858538eSMatthew G. Knepley   PetscCall(DMGetCellCoordinatesLocal(dmB, &coordsB));
2436858538eSMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)coordsA));
2446858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(dmA, coordsB));
2456858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(dmB, coordsA));
2466858538eSMatthew G. Knepley   PetscCall(PetscObjectDereference((PetscObject)coordsA));
2476858538eSMatthew G. Knepley 
2485552b385SBrandon   PetscCall(DMPlexSwapEGADSInfo_Private(dmA, dmB));
2495552b385SBrandon 
2506858538eSMatthew G. Knepley   fieldTmp                  = dmA->coordinates[0].field;
2516858538eSMatthew G. Knepley   dmA->coordinates[0].field = dmB->coordinates[0].field;
2526858538eSMatthew G. Knepley   dmB->coordinates[0].field = fieldTmp;
2536858538eSMatthew G. Knepley   fieldTmp                  = dmA->coordinates[1].field;
2546858538eSMatthew G. Knepley   dmA->coordinates[1].field = dmB->coordinates[1].field;
2556858538eSMatthew G. Knepley   dmB->coordinates[1].field = fieldTmp;
2569318fe57SMatthew G. Knepley   tmp                       = dmA->data;
2579318fe57SMatthew G. Knepley   dmA->data                 = dmB->data;
2589318fe57SMatthew G. Knepley   dmB->data                 = tmp;
2599318fe57SMatthew G. Knepley   listTmp                   = dmA->labels;
2609318fe57SMatthew G. Knepley   dmA->labels               = dmB->labels;
2619318fe57SMatthew G. Knepley   dmB->labels               = listTmp;
2629318fe57SMatthew G. Knepley   depthTmp                  = dmA->depthLabel;
2639318fe57SMatthew G. Knepley   dmA->depthLabel           = dmB->depthLabel;
2649318fe57SMatthew G. Knepley   dmB->depthLabel           = depthTmp;
2659318fe57SMatthew G. Knepley   depthTmp                  = dmA->celltypeLabel;
2669318fe57SMatthew G. Knepley   dmA->celltypeLabel        = dmB->celltypeLabel;
2679318fe57SMatthew G. Knepley   dmB->celltypeLabel        = depthTmp;
2689318fe57SMatthew G. Knepley   tmpI                      = dmA->levelup;
2699318fe57SMatthew G. Knepley   dmA->levelup              = dmB->levelup;
2709318fe57SMatthew G. Knepley   dmB->levelup              = tmpI;
2713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2729318fe57SMatthew G. Knepley }
2739318fe57SMatthew G. Knepley 
2743431e603SJed Brown PetscErrorCode DMPlexInterpolateInPlace_Internal(DM dm)
275d71ae5a4SJacob Faibussowitsch {
2769318fe57SMatthew G. Knepley   DM idm;
2779318fe57SMatthew G. Knepley 
2789318fe57SMatthew G. Knepley   PetscFunctionBegin;
2799566063dSJacob Faibussowitsch   PetscCall(DMPlexInterpolate(dm, &idm));
2809566063dSJacob Faibussowitsch   PetscCall(DMPlexCopyCoordinates(dm, idm));
28169d8a87bSksagiyam   PetscCall(DMPlexReplace_Internal(dm, &idm));
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2839318fe57SMatthew G. Knepley }
2849318fe57SMatthew G. Knepley 
2859318fe57SMatthew G. Knepley /*@C
2869318fe57SMatthew G. Knepley   DMPlexCreateCoordinateSpace - Creates a finite element space for the coordinates
2879318fe57SMatthew G. Knepley 
28820f4b53cSBarry Smith   Collective
2899318fe57SMatthew G. Knepley 
2909318fe57SMatthew G. Knepley   Input Parameters:
29160225df5SJacob Faibussowitsch + dm        - The `DMPLEX`
29220f4b53cSBarry Smith . degree    - The degree of the finite element or `PETSC_DECIDE`
2934c712d99Sksagiyam . localized - Flag to create a localized (DG) coordinate space
294e65c294aSksagiyam - project   - Flag to project current coordinates into the space
2959318fe57SMatthew G. Knepley 
2969318fe57SMatthew G. Knepley   Level: advanced
2979318fe57SMatthew G. Knepley 
298e65c294aSksagiyam .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscPointFn`, `PetscFECreateLagrange()`, `DMGetCoordinateDM()`, `DMPlexSetCoordinateMap()`
2999318fe57SMatthew G. Knepley @*/
300e65c294aSksagiyam PetscErrorCode DMPlexCreateCoordinateSpace(DM dm, PetscInt degree, PetscBool localized, PetscBool project)
301d71ae5a4SJacob Faibussowitsch {
302e44f6aebSMatthew G. Knepley   PetscFE  fe = NULL;
3039318fe57SMatthew G. Knepley   DM       cdm;
304ac9d17c7SMatthew G. Knepley   PetscInt dim, cdim, dE, qorder, height;
3059318fe57SMatthew G. Knepley 
306e44f6aebSMatthew G. Knepley   PetscFunctionBegin;
3079566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
308ac9d17c7SMatthew G. Knepley   cdim = dim;
3099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
3109318fe57SMatthew G. Knepley   qorder = degree;
311e44f6aebSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(dm, &cdm));
312d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)cdm);
313dc431b0cSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "DMPlexCreateCoordinateSpace", qorder, &qorder, NULL, 0));
314ac9d17c7SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_coordinate_dim", "Set the coordinate dimension", "DMPlexCreateCoordinateSpace", cdim, &cdim, NULL, dim));
315d0609cedSBarry Smith   PetscOptionsEnd();
3161df12153SMatthew G. Knepley   PetscCall(DMPlexGetVTKCellHeight(dm, &height));
317ac9d17c7SMatthew G. Knepley   if (cdim > dim) {
318ac9d17c7SMatthew G. Knepley     DM           cdm;
319ac9d17c7SMatthew G. Knepley     PetscSection cs, csNew;
320ac9d17c7SMatthew G. Knepley     Vec          coordinates, coordinatesNew;
321ac9d17c7SMatthew G. Knepley     VecType      vectype;
322ac9d17c7SMatthew G. Knepley     IS           idx;
323ac9d17c7SMatthew G. Knepley     PetscInt    *indices;
324ac9d17c7SMatthew G. Knepley     PetscInt     bs, n;
325ac9d17c7SMatthew G. Knepley 
326ac9d17c7SMatthew G. Knepley     // Recreate coordinate section
327ac9d17c7SMatthew G. Knepley     {
328ac9d17c7SMatthew G. Knepley       const char *fieldName = NULL, *compName = NULL;
329ac9d17c7SMatthew G. Knepley       PetscInt    Nc, pStart, pEnd;
330ac9d17c7SMatthew G. Knepley 
331ac9d17c7SMatthew G. Knepley       PetscCall(DMGetCoordinateDM(dm, &cdm));
332ac9d17c7SMatthew G. Knepley       PetscCall(DMGetLocalSection(cdm, &cs));
333ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cs), &csNew));
334ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionSetNumFields(csNew, 1));
335ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionGetFieldName(cs, 0, &fieldName));
336ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionSetFieldName(csNew, 0, fieldName));
337ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionGetFieldComponents(cs, 0, &Nc));
338ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionSetFieldComponents(csNew, 0, cdim));
339ac9d17c7SMatthew G. Knepley       for (PetscInt c = 0; c < Nc; ++c) {
340ac9d17c7SMatthew G. Knepley         PetscCall(PetscSectionGetComponentName(cs, 0, c, &compName));
341ac9d17c7SMatthew G. Knepley         PetscCall(PetscSectionSetComponentName(csNew, 0, c, compName));
342ac9d17c7SMatthew G. Knepley       }
343ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionGetChart(cs, &pStart, &pEnd));
344ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionSetChart(csNew, pStart, pEnd));
345ac9d17c7SMatthew G. Knepley       for (PetscInt p = pStart; p < pEnd; ++p) {
346530e699aSMatthew G. Knepley         PetscInt dof;
347530e699aSMatthew G. Knepley 
348530e699aSMatthew G. Knepley         PetscCall(PetscSectionGetDof(cs, p, &dof));
349530e699aSMatthew G. Knepley         if (dof) {
350ac9d17c7SMatthew G. Knepley           PetscCall(PetscSectionSetDof(csNew, p, cdim));
351ac9d17c7SMatthew G. Knepley           PetscCall(PetscSectionSetFieldDof(csNew, p, 0, cdim));
352ac9d17c7SMatthew G. Knepley         }
353530e699aSMatthew G. Knepley       }
354ac9d17c7SMatthew G. Knepley       PetscCall(PetscSectionSetUp(csNew));
355ac9d17c7SMatthew G. Knepley     }
356ac9d17c7SMatthew G. Knepley     PetscCall(DMSetLocalSection(cdm, csNew));
357ac9d17c7SMatthew G. Knepley     PetscCall(PetscSectionDestroy(&csNew));
358530e699aSMatthew G. Knepley     // Reset coordinate dimension for coordinate DM
359530e699aSMatthew G. Knepley     PetscCall(DMSetCoordinateDim(cdm, cdim));
360530e699aSMatthew G. Knepley     PetscCall(DMSetCoordinateField(cdm, NULL));
361ac9d17c7SMatthew G. Knepley     // Inject coordinates into higher dimension
362ac9d17c7SMatthew G. Knepley     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
363ac9d17c7SMatthew G. Knepley     PetscCall(VecGetBlockSize(coordinates, &bs));
364ac9d17c7SMatthew G. Knepley     PetscCheck(bs == dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension");
365ac9d17c7SMatthew G. Knepley     PetscCall(VecCreate(PetscObjectComm((PetscObject)coordinates), &coordinatesNew));
366ac9d17c7SMatthew G. Knepley     PetscCall(VecGetType(coordinates, &vectype));
367ac9d17c7SMatthew G. Knepley     PetscCall(VecSetType(coordinatesNew, vectype));
368ac9d17c7SMatthew G. Knepley     PetscCall(VecGetLocalSize(coordinates, &n));
369ac9d17c7SMatthew G. Knepley     PetscCheck(!(n % bs), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "We can only inject simple coordinates into a higher dimension");
370ac9d17c7SMatthew G. Knepley     n /= bs;
371ac9d17c7SMatthew G. Knepley     PetscCall(VecSetSizes(coordinatesNew, n * cdim, PETSC_DETERMINE));
372ac9d17c7SMatthew G. Knepley     PetscCall(VecSetUp(coordinatesNew));
373ac9d17c7SMatthew G. Knepley     PetscCall(PetscMalloc1(n * bs, &indices));
374ac9d17c7SMatthew G. Knepley     for (PetscInt i = 0; i < n; ++i)
375ac9d17c7SMatthew G. Knepley       for (PetscInt b = 0; b < bs; ++b) indices[i * bs + b] = i * cdim + b;
376ac9d17c7SMatthew G. Knepley     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n * bs, indices, PETSC_OWN_POINTER, &idx));
377ac9d17c7SMatthew G. Knepley     PetscCall(VecISCopy(coordinatesNew, idx, SCATTER_FORWARD, coordinates));
378ac9d17c7SMatthew G. Knepley     PetscCall(ISDestroy(&idx));
379ac9d17c7SMatthew G. Knepley     PetscCall(DMSetCoordinatesLocal(dm, coordinatesNew));
380ac9d17c7SMatthew G. Knepley     PetscCall(VecDestroy(&coordinatesNew));
381ac9d17c7SMatthew G. Knepley     PetscCall(DMSetCoordinateDim(dm, cdim));
382ac9d17c7SMatthew G. Knepley     {
383ac9d17c7SMatthew G. Knepley       PetscInt gn;
384ac9d17c7SMatthew G. Knepley 
385ac9d17c7SMatthew G. Knepley       PetscCall(DMGetCoordinates(dm, &coordinatesNew));
386ac9d17c7SMatthew G. Knepley       PetscCall(VecGetLocalSize(coordinatesNew, &gn));
387ac9d17c7SMatthew G. Knepley       PetscCheck(gn == n * cdim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Global coordinate size %" PetscInt_FMT " != %" PetscInt_FMT "local coordinate size", gn, n * cdim);
388ac9d17c7SMatthew G. Knepley     }
389ac9d17c7SMatthew G. Knepley     dE      = cdim;
390530e699aSMatthew G. Knepley     project = PETSC_FALSE;
391ac9d17c7SMatthew G. Knepley   }
392e44f6aebSMatthew G. Knepley   if (degree >= 0) {
393e44f6aebSMatthew G. Knepley     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
394e44f6aebSMatthew G. Knepley     PetscInt       cStart, cEnd, gct;
395dc431b0cSMatthew G. Knepley 
3961df12153SMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd));
397dc431b0cSMatthew G. Knepley     if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct));
398e44f6aebSMatthew G. Knepley     gct = (PetscInt)ct;
399462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm)));
400e44f6aebSMatthew G. Knepley     ct = (DMPolytopeType)gct;
401e44f6aebSMatthew G. Knepley     // Work around current bug in PetscDualSpaceSetUp_Lagrange()
402e44f6aebSMatthew G. Knepley     //   Can be seen in plex_tutorials-ex10_1
4034c712d99Sksagiyam     if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) {
4044c712d99Sksagiyam       PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, degree, qorder, &fe));
4054c712d99Sksagiyam       if (localized) {
4064c712d99Sksagiyam         PetscFE dgfe = NULL;
4074c712d99Sksagiyam 
4084c712d99Sksagiyam         PetscCall(PetscFECreateBrokenElement(fe, &dgfe));
4094c712d99Sksagiyam         PetscCall(PetscFEDestroy(&fe));
4104c712d99Sksagiyam         fe = dgfe;
4114f9ab2b4SJed Brown       }
4124c712d99Sksagiyam     }
4134c712d99Sksagiyam   }
4144c712d99Sksagiyam   PetscCall(DMSetCoordinateDisc(dm, fe, localized, project));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFEDestroy(&fe));
4163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4179318fe57SMatthew G. Knepley }
4189318fe57SMatthew G. Knepley 
4191df5d5c5SMatthew G. Knepley /*@
4201df5d5c5SMatthew G. Knepley   DMPlexCreateDoublet - Creates a mesh of two cells of the specified type, optionally with later refinement.
4211df5d5c5SMatthew G. Knepley 
422d083f849SBarry Smith   Collective
4231df5d5c5SMatthew G. Knepley 
4241df5d5c5SMatthew G. Knepley   Input Parameters:
425a1cb98faSBarry Smith + comm            - The communicator for the `DM` object
4261df5d5c5SMatthew G. Knepley . dim             - The spatial dimension
4271df5d5c5SMatthew G. Knepley . simplex         - Flag for simplicial cells, otherwise they are tensor product cells
4281df5d5c5SMatthew G. Knepley . interpolate     - Flag to create intermediate mesh pieces (edges, faces)
4291df5d5c5SMatthew G. Knepley - refinementLimit - A nonzero number indicates the largest admissible volume for a refined cell
4301df5d5c5SMatthew G. Knepley 
4311df5d5c5SMatthew G. Knepley   Output Parameter:
43260225df5SJacob Faibussowitsch . newdm - The `DM` object
4331df5d5c5SMatthew G. Knepley 
4341df5d5c5SMatthew G. Knepley   Level: beginner
4351df5d5c5SMatthew G. Knepley 
4361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetType()`, `DMCreate()`
4371df5d5c5SMatthew G. Knepley @*/
438d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateDoublet(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscBool interpolate, PetscReal refinementLimit, DM *newdm)
439d71ae5a4SJacob Faibussowitsch {
4401df5d5c5SMatthew G. Knepley   DM          dm;
4411df5d5c5SMatthew G. Knepley   PetscMPIInt rank;
4421df5d5c5SMatthew G. Knepley 
4431df5d5c5SMatthew G. Knepley   PetscFunctionBegin;
4449566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, &dm));
4459566063dSJacob Faibussowitsch   PetscCall(DMSetType(dm, DMPLEX));
4469566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
44746139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
4489566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
449ce78fa2fSMatthew G. Knepley   switch (dim) {
450ce78fa2fSMatthew G. Knepley   case 2:
4519566063dSJacob Faibussowitsch     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "triangular"));
4529566063dSJacob Faibussowitsch     else PetscCall(PetscObjectSetName((PetscObject)dm, "quadrilateral"));
453ce78fa2fSMatthew G. Knepley     break;
454ce78fa2fSMatthew G. Knepley   case 3:
4559566063dSJacob Faibussowitsch     if (simplex) PetscCall(PetscObjectSetName((PetscObject)dm, "tetrahedral"));
4569566063dSJacob Faibussowitsch     else PetscCall(PetscObjectSetName((PetscObject)dm, "hexahedral"));
457ce78fa2fSMatthew G. Knepley     break;
458d71ae5a4SJacob Faibussowitsch   default:
459d71ae5a4SJacob Faibussowitsch     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
460ce78fa2fSMatthew G. Knepley   }
4611df5d5c5SMatthew G. Knepley   if (rank) {
4621df5d5c5SMatthew G. Knepley     PetscInt numPoints[2] = {0, 0};
4639566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, NULL, NULL, NULL, NULL));
4641df5d5c5SMatthew G. Knepley   } else {
4651df5d5c5SMatthew G. Knepley     switch (dim) {
4661df5d5c5SMatthew G. Knepley     case 2:
4671df5d5c5SMatthew G. Knepley       if (simplex) {
4681df5d5c5SMatthew G. Knepley         PetscInt    numPoints[2]        = {4, 2};
4691df5d5c5SMatthew G. Knepley         PetscInt    coneSize[6]         = {3, 3, 0, 0, 0, 0};
4701df5d5c5SMatthew G. Knepley         PetscInt    cones[6]            = {2, 3, 4, 5, 4, 3};
4711df5d5c5SMatthew G. Knepley         PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
4721df5d5c5SMatthew G. Knepley         PetscScalar vertexCoords[8]     = {-0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.5, 0.5};
4731df5d5c5SMatthew G. Knepley 
4749566063dSJacob Faibussowitsch         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4751df5d5c5SMatthew G. Knepley       } else {
4761df5d5c5SMatthew G. Knepley         PetscInt    numPoints[2]        = {6, 2};
4771df5d5c5SMatthew G. Knepley         PetscInt    coneSize[8]         = {4, 4, 0, 0, 0, 0, 0, 0};
4781df5d5c5SMatthew G. Knepley         PetscInt    cones[8]            = {2, 3, 4, 5, 3, 6, 7, 4};
4791df5d5c5SMatthew G. Knepley         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
4801df5d5c5SMatthew G. Knepley         PetscScalar vertexCoords[12]    = {-1.0, -0.5, 0.0, -0.5, 0.0, 0.5, -1.0, 0.5, 1.0, -0.5, 1.0, 0.5};
4811df5d5c5SMatthew G. Knepley 
4829566063dSJacob Faibussowitsch         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4831df5d5c5SMatthew G. Knepley       }
4841df5d5c5SMatthew G. Knepley       break;
4851df5d5c5SMatthew G. Knepley     case 3:
4861df5d5c5SMatthew G. Knepley       if (simplex) {
4871df5d5c5SMatthew G. Knepley         PetscInt    numPoints[2]        = {5, 2};
4881df5d5c5SMatthew G. Knepley         PetscInt    coneSize[7]         = {4, 4, 0, 0, 0, 0, 0};
4891df5d5c5SMatthew G. Knepley         PetscInt    cones[8]            = {4, 3, 5, 2, 5, 3, 4, 6};
4901df5d5c5SMatthew G. Knepley         PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
4911df5d5c5SMatthew G. Knepley         PetscScalar vertexCoords[15]    = {-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0};
4921df5d5c5SMatthew G. Knepley 
4939566063dSJacob Faibussowitsch         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
4941df5d5c5SMatthew G. Knepley       } else {
4951df5d5c5SMatthew G. Knepley         PetscInt    numPoints[2]         = {12, 2};
4961df5d5c5SMatthew G. Knepley         PetscInt    coneSize[14]         = {8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
4971df5d5c5SMatthew G. Knepley         PetscInt    cones[16]            = {2, 3, 4, 5, 6, 7, 8, 9, 5, 4, 10, 11, 7, 12, 13, 8};
4981df5d5c5SMatthew G. Knepley         PetscInt    coneOrientations[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
4999371c9d4SSatish Balay         PetscScalar vertexCoords[36]     = {-1.0, -0.5, -0.5, -1.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, -1.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, -1.0, 0.5, 0.5, 1.0, 0.5, -0.5, 1.0, -0.5, -0.5, 1.0, -0.5, 0.5, 1.0, 0.5, 0.5};
5001df5d5c5SMatthew G. Knepley 
5019566063dSJacob Faibussowitsch         PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
5021df5d5c5SMatthew G. Knepley       }
5031df5d5c5SMatthew G. Knepley       break;
504d71ae5a4SJacob Faibussowitsch     default:
505d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, dim);
5061df5d5c5SMatthew G. Knepley     }
5071df5d5c5SMatthew G. Knepley   }
50846139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
5091df5d5c5SMatthew G. Knepley   *newdm = dm;
5101df5d5c5SMatthew G. Knepley   if (refinementLimit > 0.0) {
5111df5d5c5SMatthew G. Knepley     DM          rdm;
5121df5d5c5SMatthew G. Knepley     const char *name;
5131df5d5c5SMatthew G. Knepley 
5149566063dSJacob Faibussowitsch     PetscCall(DMPlexSetRefinementUniform(*newdm, PETSC_FALSE));
5159566063dSJacob Faibussowitsch     PetscCall(DMPlexSetRefinementLimit(*newdm, refinementLimit));
5169566063dSJacob Faibussowitsch     PetscCall(DMRefine(*newdm, comm, &rdm));
5179566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)*newdm, &name));
5189566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)rdm, name));
5199566063dSJacob Faibussowitsch     PetscCall(DMDestroy(newdm));
5201df5d5c5SMatthew G. Knepley     *newdm = rdm;
5211df5d5c5SMatthew G. Knepley   }
5221df5d5c5SMatthew G. Knepley   if (interpolate) {
5235fd9971aSMatthew G. Knepley     DM idm;
5241df5d5c5SMatthew G. Knepley 
5259566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*newdm, &idm));
5269566063dSJacob Faibussowitsch     PetscCall(DMDestroy(newdm));
5271df5d5c5SMatthew G. Knepley     *newdm = idm;
5281df5d5c5SMatthew G. Knepley   }
5293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5301df5d5c5SMatthew G. Knepley }
5311df5d5c5SMatthew G. Knepley 
532d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
533d71ae5a4SJacob Faibussowitsch {
5349318fe57SMatthew G. Knepley   const PetscInt numVertices    = 2;
5359318fe57SMatthew G. Knepley   PetscInt       markerRight    = 1;
5369318fe57SMatthew G. Knepley   PetscInt       markerLeft     = 1;
5379318fe57SMatthew G. Knepley   PetscBool      markerSeparate = PETSC_FALSE;
5389318fe57SMatthew G. Knepley   Vec            coordinates;
5399318fe57SMatthew G. Knepley   PetscSection   coordSection;
5409318fe57SMatthew G. Knepley   PetscScalar   *coords;
5419318fe57SMatthew G. Knepley   PetscInt       coordSize;
5429318fe57SMatthew G. Knepley   PetscMPIInt    rank;
5439318fe57SMatthew G. Knepley   PetscInt       cdim = 1, v;
544552f7358SJed Brown 
5459318fe57SMatthew G. Knepley   PetscFunctionBegin;
5469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
5479318fe57SMatthew G. Knepley   if (markerSeparate) {
5489318fe57SMatthew G. Knepley     markerRight = 2;
5499318fe57SMatthew G. Knepley     markerLeft  = 1;
5509318fe57SMatthew G. Knepley   }
5519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
552c5853193SPierre Jolivet   if (rank == 0) {
5539566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numVertices));
5549566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
5559566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "marker", 0, markerLeft));
5569566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "marker", 1, markerRight));
5579318fe57SMatthew G. Knepley   }
5589566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
5599566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
5609318fe57SMatthew G. Knepley   /* Build coordinates */
5619566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, cdim));
5629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
5639566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
5649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, 0, numVertices));
5659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
5669318fe57SMatthew G. Knepley   for (v = 0; v < numVertices; ++v) {
5679566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
5689566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
5699318fe57SMatthew G. Knepley   }
5709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
5719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
5729566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
5739566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
5749566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
5759566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, cdim));
5769566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
5779566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
5789318fe57SMatthew G. Knepley   coords[0] = lower[0];
5799318fe57SMatthew G. Knepley   coords[1] = upper[0];
5809566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
5819566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
5829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
5833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5849318fe57SMatthew G. Knepley }
58526492d91SMatthew G. Knepley 
586d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[])
587d71ae5a4SJacob Faibussowitsch {
5881df21d24SMatthew G. Knepley   const PetscInt numVertices    = (edges[0] + 1) * (edges[1] + 1);
5891df21d24SMatthew G. Knepley   const PetscInt numEdges       = edges[0] * (edges[1] + 1) + (edges[0] + 1) * edges[1];
590552f7358SJed Brown   PetscInt       markerTop      = 1;
591552f7358SJed Brown   PetscInt       markerBottom   = 1;
592552f7358SJed Brown   PetscInt       markerRight    = 1;
593552f7358SJed Brown   PetscInt       markerLeft     = 1;
594552f7358SJed Brown   PetscBool      markerSeparate = PETSC_FALSE;
595552f7358SJed Brown   Vec            coordinates;
596552f7358SJed Brown   PetscSection   coordSection;
597552f7358SJed Brown   PetscScalar   *coords;
598552f7358SJed Brown   PetscInt       coordSize;
599552f7358SJed Brown   PetscMPIInt    rank;
600552f7358SJed Brown   PetscInt       v, vx, vy;
601552f7358SJed Brown 
602552f7358SJed Brown   PetscFunctionBegin;
6039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
604552f7358SJed Brown   if (markerSeparate) {
6051df21d24SMatthew G. Knepley     markerTop    = 3;
6061df21d24SMatthew G. Knepley     markerBottom = 1;
6071df21d24SMatthew G. Knepley     markerRight  = 2;
6081df21d24SMatthew G. Knepley     markerLeft   = 4;
609552f7358SJed Brown   }
6109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
611dd400576SPatrick Sanan   if (rank == 0) {
612552f7358SJed Brown     PetscInt e, ex, ey;
613552f7358SJed Brown 
6149566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numEdges + numVertices));
61548a46eb9SPierre Jolivet     for (e = 0; e < numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
6169566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
617552f7358SJed Brown     for (vx = 0; vx <= edges[0]; vx++) {
618552f7358SJed Brown       for (ey = 0; ey < edges[1]; ey++) {
619552f7358SJed Brown         PetscInt edge   = vx * edges[1] + ey + edges[0] * (edges[1] + 1);
620552f7358SJed Brown         PetscInt vertex = ey * (edges[0] + 1) + vx + numEdges;
621da80777bSKarl Rupp         PetscInt cone[2];
622552f7358SJed Brown 
6239371c9d4SSatish Balay         cone[0] = vertex;
6249371c9d4SSatish Balay         cone[1] = vertex + edges[0] + 1;
6259566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, edge, cone));
626552f7358SJed Brown         if (vx == edges[0]) {
6279566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
6289566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
629552f7358SJed Brown           if (ey == edges[1] - 1) {
6309566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
6319566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerRight));
632552f7358SJed Brown           }
633552f7358SJed Brown         } else if (vx == 0) {
6349566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
6359566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
636552f7358SJed Brown           if (ey == edges[1] - 1) {
6379566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
6389566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerLeft));
639552f7358SJed Brown           }
640552f7358SJed Brown         }
641552f7358SJed Brown       }
642552f7358SJed Brown     }
643552f7358SJed Brown     for (vy = 0; vy <= edges[1]; vy++) {
644552f7358SJed Brown       for (ex = 0; ex < edges[0]; ex++) {
645552f7358SJed Brown         PetscInt edge   = vy * edges[0] + ex;
646552f7358SJed Brown         PetscInt vertex = vy * (edges[0] + 1) + ex + numEdges;
647da80777bSKarl Rupp         PetscInt cone[2];
648552f7358SJed Brown 
6499371c9d4SSatish Balay         cone[0] = vertex;
6509371c9d4SSatish Balay         cone[1] = vertex + 1;
6519566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, edge, cone));
652552f7358SJed Brown         if (vy == edges[1]) {
6539566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
6549566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
655552f7358SJed Brown           if (ex == edges[0] - 1) {
6569566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
6579566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerTop));
658552f7358SJed Brown           }
659552f7358SJed Brown         } else if (vy == 0) {
6609566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
6619566063dSJacob Faibussowitsch           PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
662552f7358SJed Brown           if (ex == edges[0] - 1) {
6639566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
6649566063dSJacob Faibussowitsch             PetscCall(DMSetLabelValue(dm, "Face Sets", cone[1], markerBottom));
665552f7358SJed Brown           }
666552f7358SJed Brown         }
667552f7358SJed Brown       }
668552f7358SJed Brown     }
669552f7358SJed Brown   }
6709566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
6719566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
672552f7358SJed Brown   /* Build coordinates */
6739566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, 2));
6749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6759566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, numEdges, numEdges + numVertices));
6779566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
678552f7358SJed Brown   for (v = numEdges; v < numEdges + numVertices; ++v) {
6799566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, 2));
6809566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
681552f7358SJed Brown   }
6829566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
6839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
6849566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
6859566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
6869566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
6879566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, 2));
6889566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
6899566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
690552f7358SJed Brown   for (vy = 0; vy <= edges[1]; ++vy) {
691552f7358SJed Brown     for (vx = 0; vx <= edges[0]; ++vx) {
692552f7358SJed Brown       coords[(vy * (edges[0] + 1) + vx) * 2 + 0] = lower[0] + ((upper[0] - lower[0]) / edges[0]) * vx;
693552f7358SJed Brown       coords[(vy * (edges[0] + 1) + vx) * 2 + 1] = lower[1] + ((upper[1] - lower[1]) / edges[1]) * vy;
694552f7358SJed Brown     }
695552f7358SJed Brown   }
6969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
6979566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
6989566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
6993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
700552f7358SJed Brown }
701552f7358SJed Brown 
702d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt faces[])
703d71ae5a4SJacob Faibussowitsch {
7049e8abbc3SMichael Lange   PetscInt     vertices[3], numVertices;
7057b59f5a9SMichael Lange   PetscInt     numFaces       = 2 * faces[0] * faces[1] + 2 * faces[1] * faces[2] + 2 * faces[0] * faces[2];
706c2df9bbfSMatthew G. Knepley   PetscInt     markerTop      = 1;
707c2df9bbfSMatthew G. Knepley   PetscInt     markerBottom   = 1;
708c2df9bbfSMatthew G. Knepley   PetscInt     markerFront    = 1;
709c2df9bbfSMatthew G. Knepley   PetscInt     markerBack     = 1;
710c2df9bbfSMatthew G. Knepley   PetscInt     markerRight    = 1;
711c2df9bbfSMatthew G. Knepley   PetscInt     markerLeft     = 1;
712c2df9bbfSMatthew G. Knepley   PetscBool    markerSeparate = PETSC_FALSE;
713552f7358SJed Brown   Vec          coordinates;
714552f7358SJed Brown   PetscSection coordSection;
715552f7358SJed Brown   PetscScalar *coords;
716552f7358SJed Brown   PetscInt     coordSize;
717552f7358SJed Brown   PetscMPIInt  rank;
718552f7358SJed Brown   PetscInt     v, vx, vy, vz;
7197b59f5a9SMichael Lange   PetscInt     voffset, iface = 0, cone[4];
720552f7358SJed Brown 
721552f7358SJed Brown   PetscFunctionBegin;
7221dca8a05SBarry Smith   PetscCheck(faces[0] >= 1 && faces[1] >= 1 && faces[2] >= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Must have at least 1 face per side");
7239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
724c2df9bbfSMatthew G. Knepley   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
725c2df9bbfSMatthew G. Knepley   if (markerSeparate) {
726c2df9bbfSMatthew G. Knepley     markerBottom = 1;
727c2df9bbfSMatthew G. Knepley     markerTop    = 2;
728c2df9bbfSMatthew G. Knepley     markerFront  = 3;
729c2df9bbfSMatthew G. Knepley     markerBack   = 4;
730c2df9bbfSMatthew G. Knepley     markerRight  = 5;
731c2df9bbfSMatthew G. Knepley     markerLeft   = 6;
732c2df9bbfSMatthew G. Knepley   }
7339371c9d4SSatish Balay   vertices[0] = faces[0] + 1;
7349371c9d4SSatish Balay   vertices[1] = faces[1] + 1;
7359371c9d4SSatish Balay   vertices[2] = faces[2] + 1;
7369e8abbc3SMichael Lange   numVertices = vertices[0] * vertices[1] * vertices[2];
737dd400576SPatrick Sanan   if (rank == 0) {
738552f7358SJed Brown     PetscInt f;
739552f7358SJed Brown 
7409566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numFaces + numVertices));
74148a46eb9SPierre Jolivet     for (f = 0; f < numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
7429566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
7437b59f5a9SMichael Lange 
7447b59f5a9SMichael Lange     /* Side 0 (Top) */
7457b59f5a9SMichael Lange     for (vy = 0; vy < faces[1]; vy++) {
7467b59f5a9SMichael Lange       for (vx = 0; vx < faces[0]; vx++) {
7477b59f5a9SMichael Lange         voffset = numFaces + vertices[0] * vertices[1] * (vertices[2] - 1) + vy * vertices[0] + vx;
7489371c9d4SSatish Balay         cone[0] = voffset;
7499371c9d4SSatish Balay         cone[1] = voffset + 1;
7509371c9d4SSatish Balay         cone[2] = voffset + vertices[0] + 1;
7519371c9d4SSatish Balay         cone[3] = voffset + vertices[0];
7529566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
753c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerTop));
754c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerTop));
755c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerTop));
756c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerTop));
757c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerTop));
7587b59f5a9SMichael Lange         iface++;
759552f7358SJed Brown       }
760552f7358SJed Brown     }
7617b59f5a9SMichael Lange 
7627b59f5a9SMichael Lange     /* Side 1 (Bottom) */
7637b59f5a9SMichael Lange     for (vy = 0; vy < faces[1]; vy++) {
7647b59f5a9SMichael Lange       for (vx = 0; vx < faces[0]; vx++) {
7657b59f5a9SMichael Lange         voffset = numFaces + vy * (faces[0] + 1) + vx;
7669371c9d4SSatish Balay         cone[0] = voffset + 1;
7679371c9d4SSatish Balay         cone[1] = voffset;
7689371c9d4SSatish Balay         cone[2] = voffset + vertices[0];
7699371c9d4SSatish Balay         cone[3] = voffset + vertices[0] + 1;
7709566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
771c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBottom));
772c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBottom));
773c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBottom));
774c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerBottom));
775c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 1, markerBottom));
7767b59f5a9SMichael Lange         iface++;
777552f7358SJed Brown       }
778552f7358SJed Brown     }
7797b59f5a9SMichael Lange 
7807b59f5a9SMichael Lange     /* Side 2 (Front) */
7817b59f5a9SMichael Lange     for (vz = 0; vz < faces[2]; vz++) {
7827b59f5a9SMichael Lange       for (vx = 0; vx < faces[0]; vx++) {
7837b59f5a9SMichael Lange         voffset = numFaces + vz * vertices[0] * vertices[1] + vx;
7849371c9d4SSatish Balay         cone[0] = voffset;
7859371c9d4SSatish Balay         cone[1] = voffset + 1;
7869371c9d4SSatish Balay         cone[2] = voffset + vertices[0] * vertices[1] + 1;
7879371c9d4SSatish Balay         cone[3] = voffset + vertices[0] * vertices[1];
7889566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
789c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerFront));
790c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerFront));
791c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerFront));
792c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerFront));
793c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerFront));
7947b59f5a9SMichael Lange         iface++;
795552f7358SJed Brown       }
7967b59f5a9SMichael Lange     }
7977b59f5a9SMichael Lange 
7987b59f5a9SMichael Lange     /* Side 3 (Back) */
7997b59f5a9SMichael Lange     for (vz = 0; vz < faces[2]; vz++) {
8007b59f5a9SMichael Lange       for (vx = 0; vx < faces[0]; vx++) {
8017b59f5a9SMichael Lange         voffset = numFaces + vz * vertices[0] * vertices[1] + vertices[0] * (vertices[1] - 1) + vx;
8029371c9d4SSatish Balay         cone[0] = voffset + vertices[0] * vertices[1];
8039371c9d4SSatish Balay         cone[1] = voffset + vertices[0] * vertices[1] + 1;
8049371c9d4SSatish Balay         cone[2] = voffset + 1;
8059371c9d4SSatish Balay         cone[3] = voffset;
8069566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
807c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerBack));
808c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerBack));
809c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 1, markerBack));
810c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerBack));
811c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 1, markerBack));
8127b59f5a9SMichael Lange         iface++;
8137b59f5a9SMichael Lange       }
8147b59f5a9SMichael Lange     }
8157b59f5a9SMichael Lange 
8167b59f5a9SMichael Lange     /* Side 4 (Left) */
8177b59f5a9SMichael Lange     for (vz = 0; vz < faces[2]; vz++) {
8187b59f5a9SMichael Lange       for (vy = 0; vy < faces[1]; vy++) {
8197b59f5a9SMichael Lange         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0];
8209371c9d4SSatish Balay         cone[0] = voffset;
8219371c9d4SSatish Balay         cone[1] = voffset + vertices[0] * vertices[1];
8229371c9d4SSatish Balay         cone[2] = voffset + vertices[0] * vertices[1] + vertices[0];
8239371c9d4SSatish Balay         cone[3] = voffset + vertices[0];
8249566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
825c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerLeft));
826c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerLeft));
827c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerLeft));
828c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[1] + 0, markerLeft));
829c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerLeft));
8307b59f5a9SMichael Lange         iface++;
8317b59f5a9SMichael Lange       }
8327b59f5a9SMichael Lange     }
8337b59f5a9SMichael Lange 
8347b59f5a9SMichael Lange     /* Side 5 (Right) */
8357b59f5a9SMichael Lange     for (vz = 0; vz < faces[2]; vz++) {
8367b59f5a9SMichael Lange       for (vy = 0; vy < faces[1]; vy++) {
837aab5bcd8SJed Brown         voffset = numFaces + vz * vertices[0] * vertices[1] + vy * vertices[0] + faces[0];
8389371c9d4SSatish Balay         cone[0] = voffset + vertices[0] * vertices[1];
8399371c9d4SSatish Balay         cone[1] = voffset;
8409371c9d4SSatish Balay         cone[2] = voffset + vertices[0];
8419371c9d4SSatish Balay         cone[3] = voffset + vertices[0] * vertices[1] + vertices[0];
8429566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, iface, cone));
843c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", iface, markerRight));
844c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + 0, markerRight));
845c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] + 0, markerRight));
846c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + 0, markerRight));
847c2df9bbfSMatthew G. Knepley         PetscCall(DMSetLabelValue(dm, "marker", voffset + vertices[0] * vertices[1] + vertices[0], markerRight));
8487b59f5a9SMichael Lange         iface++;
8497b59f5a9SMichael Lange       }
850552f7358SJed Brown     }
851552f7358SJed Brown   }
8529566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
8539566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
854552f7358SJed Brown   /* Build coordinates */
8559566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, 3));
8569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
8579566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
8589566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, numFaces, numFaces + numVertices));
8599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
860552f7358SJed Brown   for (v = numFaces; v < numFaces + numVertices; ++v) {
8619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, 3));
8629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
863552f7358SJed Brown   }
8649566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
8659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
8669566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
8679566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
8689566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
8699566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, 3));
8709566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
8719566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
872552f7358SJed Brown   for (vz = 0; vz <= faces[2]; ++vz) {
873552f7358SJed Brown     for (vy = 0; vy <= faces[1]; ++vy) {
874552f7358SJed Brown       for (vx = 0; vx <= faces[0]; ++vx) {
875552f7358SJed Brown         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 0] = lower[0] + ((upper[0] - lower[0]) / faces[0]) * vx;
876552f7358SJed Brown         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 1] = lower[1] + ((upper[1] - lower[1]) / faces[1]) * vy;
877552f7358SJed Brown         coords[((vz * (faces[1] + 1) + vy) * (faces[0] + 1) + vx) * 3 + 2] = lower[2] + ((upper[2] - lower[2]) / faces[2]) * vz;
878552f7358SJed Brown       }
879552f7358SJed Brown     }
880552f7358SJed Brown   }
8819566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
8829566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
8839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
8843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
885552f7358SJed Brown }
886552f7358SJed Brown 
887d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxSurfaceMesh_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate)
888d71ae5a4SJacob Faibussowitsch {
8899318fe57SMatthew G. Knepley   PetscFunctionBegin;
8909318fe57SMatthew G. Knepley   PetscValidLogicalCollectiveInt(dm, dim, 2);
89146139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
8929566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim - 1));
8939566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, dim));
8949318fe57SMatthew G. Knepley   switch (dim) {
895d71ae5a4SJacob Faibussowitsch   case 1:
896d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_1D_Internal(dm, lower, upper, faces));
897d71ae5a4SJacob Faibussowitsch     break;
898d71ae5a4SJacob Faibussowitsch   case 2:
899d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_2D_Internal(dm, lower, upper, faces));
900d71ae5a4SJacob Faibussowitsch     break;
901d71ae5a4SJacob Faibussowitsch   case 3:
902d71ae5a4SJacob Faibussowitsch     PetscCall(DMPlexCreateBoxSurfaceMesh_Tensor_3D_Internal(dm, lower, upper, faces));
903d71ae5a4SJacob Faibussowitsch     break;
904d71ae5a4SJacob Faibussowitsch   default:
905d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Dimension not supported: %" PetscInt_FMT, dim);
9069318fe57SMatthew G. Knepley   }
90746139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
9089566063dSJacob Faibussowitsch   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
9093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9109318fe57SMatthew G. Knepley }
9119318fe57SMatthew G. Knepley 
9129318fe57SMatthew G. Knepley /*@C
9139318fe57SMatthew G. Knepley   DMPlexCreateBoxSurfaceMesh - Creates a mesh on the surface of the tensor product of unit intervals (box) using tensor cells (hexahedra).
9149318fe57SMatthew G. Knepley 
9159318fe57SMatthew G. Knepley   Collective
9169318fe57SMatthew G. Knepley 
9179318fe57SMatthew G. Knepley   Input Parameters:
918a1cb98faSBarry Smith + comm        - The communicator for the `DM` object
91920f4b53cSBarry Smith . dim         - The spatial dimension of the box, so the resulting mesh is has dimension `dim`-1
92020f4b53cSBarry Smith . faces       - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
92120f4b53cSBarry Smith . lower       - The lower left corner, or `NULL` for (0, 0, 0)
92220f4b53cSBarry Smith . upper       - The upper right corner, or `NULL` for (1, 1, 1)
9239318fe57SMatthew G. Knepley - interpolate - Flag to create intermediate mesh pieces (edges, faces)
9249318fe57SMatthew G. Knepley 
9259318fe57SMatthew G. Knepley   Output Parameter:
926a1cb98faSBarry Smith . dm - The `DM` object
9279318fe57SMatthew G. Knepley 
9289318fe57SMatthew G. Knepley   Level: beginner
9299318fe57SMatthew G. Knepley 
9301cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateBoxMesh()`, `DMPlexCreateFromFile()`, `DMSetType()`, `DMCreate()`
9319318fe57SMatthew G. Knepley @*/
932d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBoxSurfaceMesh(MPI_Comm comm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], PetscBool interpolate, DM *dm)
933d71ae5a4SJacob Faibussowitsch {
9349318fe57SMatthew G. Knepley   PetscInt  fac[3] = {1, 1, 1};
9359318fe57SMatthew G. Knepley   PetscReal low[3] = {0, 0, 0};
9369318fe57SMatthew G. Knepley   PetscReal upp[3] = {1, 1, 1};
9379318fe57SMatthew G. Knepley 
9389318fe57SMatthew G. Knepley   PetscFunctionBegin;
9399566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
9409566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
9419566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(*dm, dim, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, interpolate));
9423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9439318fe57SMatthew G. Knepley }
9449318fe57SMatthew G. Knepley 
945d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateLineMesh_Internal(DM dm, PetscInt segments, PetscReal lower, PetscReal upper, DMBoundaryType bd)
946d71ae5a4SJacob Faibussowitsch {
947fdbf62faSLisandro Dalcin   PetscInt     i, fStart, fEnd, numCells = 0, numVerts = 0;
948fdbf62faSLisandro Dalcin   PetscInt     numPoints[2], *coneSize, *cones, *coneOrientations;
949fdbf62faSLisandro Dalcin   PetscScalar *vertexCoords;
950fdbf62faSLisandro Dalcin   PetscReal    L, maxCell;
951fdbf62faSLisandro Dalcin   PetscBool    markerSeparate = PETSC_FALSE;
952fdbf62faSLisandro Dalcin   PetscInt     markerLeft = 1, faceMarkerLeft = 1;
953fdbf62faSLisandro Dalcin   PetscInt     markerRight = 1, faceMarkerRight = 2;
954fdbf62faSLisandro Dalcin   PetscBool    wrap = (bd == DM_BOUNDARY_PERIODIC || bd == DM_BOUNDARY_TWIST) ? PETSC_TRUE : PETSC_FALSE;
955fdbf62faSLisandro Dalcin   PetscMPIInt  rank;
956fdbf62faSLisandro Dalcin 
957fdbf62faSLisandro Dalcin   PetscFunctionBegin;
9584f572ea9SToby Isaac   PetscAssertPointer(dm, 1);
959fdbf62faSLisandro Dalcin 
9609566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, 1));
9619566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "marker"));
9629566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "Face Sets"));
963fdbf62faSLisandro Dalcin 
9649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
965dd400576SPatrick Sanan   if (rank == 0) numCells = segments;
966dd400576SPatrick Sanan   if (rank == 0) numVerts = segments + (wrap ? 0 : 1);
967fdbf62faSLisandro Dalcin 
9689371c9d4SSatish Balay   numPoints[0] = numVerts;
9699371c9d4SSatish Balay   numPoints[1] = numCells;
9709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(numCells + numVerts, &coneSize, numCells * 2, &cones, numCells + numVerts, &coneOrientations, numVerts, &vertexCoords));
9719566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(coneOrientations, numCells + numVerts));
972ad540459SPierre Jolivet   for (i = 0; i < numCells; ++i) coneSize[i] = 2;
973ad540459SPierre Jolivet   for (i = 0; i < numVerts; ++i) coneSize[numCells + i] = 0;
9749371c9d4SSatish Balay   for (i = 0; i < numCells; ++i) {
9759371c9d4SSatish Balay     cones[2 * i]     = numCells + i % numVerts;
9769371c9d4SSatish Balay     cones[2 * i + 1] = numCells + (i + 1) % numVerts;
9779371c9d4SSatish Balay   }
978ad540459SPierre Jolivet   for (i = 0; i < numVerts; ++i) vertexCoords[i] = lower + (upper - lower) * ((PetscReal)i / (PetscReal)numCells);
9799566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateFromDAG(dm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
9809566063dSJacob Faibussowitsch   PetscCall(PetscFree4(coneSize, cones, coneOrientations, vertexCoords));
981fdbf62faSLisandro Dalcin 
9829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
9839371c9d4SSatish Balay   if (markerSeparate) {
9849371c9d4SSatish Balay     markerLeft  = faceMarkerLeft;
9859371c9d4SSatish Balay     markerRight = faceMarkerRight;
9869371c9d4SSatish Balay   }
987dd400576SPatrick Sanan   if (!wrap && rank == 0) {
9889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
9899566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "marker", fStart, markerLeft));
9909566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "marker", fEnd - 1, markerRight));
9919566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "Face Sets", fStart, faceMarkerLeft));
9929566063dSJacob Faibussowitsch     PetscCall(DMSetLabelValue(dm, "Face Sets", fEnd - 1, faceMarkerRight));
993fdbf62faSLisandro Dalcin   }
994fdbf62faSLisandro Dalcin   if (wrap) {
995fdbf62faSLisandro Dalcin     L       = upper - lower;
996fdbf62faSLisandro Dalcin     maxCell = (PetscReal)1.1 * (L / (PetscReal)PetscMax(1, segments));
9974fb89dddSMatthew G. Knepley     PetscCall(DMSetPeriodicity(dm, &maxCell, &lower, &L));
998fdbf62faSLisandro Dalcin   }
9999566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
10003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1001fdbf62faSLisandro Dalcin }
1002fdbf62faSLisandro Dalcin 
10034054ae39SJames Wright // Creates "Face Sets" label based on the standard box labeling conventions
1004d7d2d1d2SJames Wright static PetscErrorCode DMPlexSetBoxLabel_Internal(DM dm, const DMBoundaryType periodicity[])
10054054ae39SJames Wright {
10066ff49feeSJames Wright   DM              cdm;
10076ff49feeSJames Wright   PetscSection    csection;
10086ff49feeSJames Wright   Vec             coordinates;
10094054ae39SJames Wright   DMLabel         label;
10106ff49feeSJames Wright   IS              faces_is;
10112b4f33d9SJames Wright   PetscInt        dim, num_face = 0;
10124054ae39SJames Wright   const PetscInt *faces;
10134054ae39SJames Wright   PetscInt        faceMarkerBottom, faceMarkerTop, faceMarkerFront, faceMarkerBack, faceMarkerRight, faceMarkerLeft;
10144054ae39SJames Wright 
10154054ae39SJames Wright   PetscFunctionBeginUser;
10164054ae39SJames Wright   PetscCall(DMGetDimension(dm, &dim));
1017d7c1f440SPierre Jolivet   PetscCheck((dim == 2) || (dim == 3), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMPlex box labeling only supports 2D and 3D meshes, received DM of dimension %" PetscInt_FMT, dim);
10184054ae39SJames Wright   // Get Face Sets label
10194054ae39SJames Wright   PetscCall(DMGetLabel(dm, "Face Sets", &label));
10204054ae39SJames Wright   if (label) {
10214054ae39SJames Wright     PetscCall(DMLabelReset(label));
10224054ae39SJames Wright   } else {
10234054ae39SJames Wright     PetscCall(DMCreateLabel(dm, "Face Sets"));
10244054ae39SJames Wright     PetscCall(DMGetLabel(dm, "Face Sets", &label));
10254054ae39SJames Wright   }
10264054ae39SJames Wright   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
10276ff49feeSJames Wright   PetscCall(DMGetStratumIS(dm, "Face Sets", 1, &faces_is));
10284054ae39SJames Wright 
10294054ae39SJames Wright   switch (dim) {
10304054ae39SJames Wright   case 2:
10314054ae39SJames Wright     faceMarkerTop    = 3;
10324054ae39SJames Wright     faceMarkerBottom = 1;
10334054ae39SJames Wright     faceMarkerRight  = 2;
10344054ae39SJames Wright     faceMarkerLeft   = 4;
10354054ae39SJames Wright     break;
10364054ae39SJames Wright   case 3:
10374054ae39SJames Wright     faceMarkerBottom = 1;
10384054ae39SJames Wright     faceMarkerTop    = 2;
10394054ae39SJames Wright     faceMarkerFront  = 3;
10404054ae39SJames Wright     faceMarkerBack   = 4;
10414054ae39SJames Wright     faceMarkerRight  = 5;
10424054ae39SJames Wright     faceMarkerLeft   = 6;
10434054ae39SJames Wright     break;
10444054ae39SJames Wright   default:
10454054ae39SJames Wright     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
10464054ae39SJames Wright   }
10474054ae39SJames Wright 
10482b4f33d9SJames Wright   if (faces_is) PetscCall(ISGetLocalSize(faces_is, &num_face));
10492b4f33d9SJames Wright   if (faces_is) PetscCall(ISGetIndices(faces_is, &faces));
10506ff49feeSJames Wright   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
10516ff49feeSJames Wright   PetscCall(DMGetCoordinateDM(dm, &cdm));
10526ff49feeSJames Wright   PetscCall(DMGetLocalSection(cdm, &csection));
10534054ae39SJames Wright   for (PetscInt f = 0; f < num_face; ++f) {
10546ff49feeSJames Wright     PetscScalar *coords = NULL;
10556ff49feeSJames Wright     PetscInt     face = faces[f], flip = 1, label_value = -1, coords_size;
10564054ae39SJames Wright 
10574054ae39SJames Wright     { // Determine if orientation of face is flipped
10584054ae39SJames Wright       PetscInt        num_cells_support, num_faces, start = -1;
10594054ae39SJames Wright       const PetscInt *orients, *cell_faces, *cells;
10604054ae39SJames Wright 
10614054ae39SJames Wright       PetscCall(DMPlexGetSupport(dm, face, &cells));
10624054ae39SJames Wright       PetscCall(DMPlexGetSupportSize(dm, face, &num_cells_support));
10634054ae39SJames Wright       PetscCheck(num_cells_support == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Expected one cell in support of exterior face, but got %" PetscInt_FMT " cells", num_cells_support);
10644054ae39SJames Wright       PetscCall(DMPlexGetCone(dm, cells[0], &cell_faces));
10654054ae39SJames Wright       PetscCall(DMPlexGetConeSize(dm, cells[0], &num_faces));
10664054ae39SJames Wright       for (PetscInt i = 0; i < num_faces; i++) {
10674054ae39SJames Wright         if (cell_faces[i] == face) start = i;
10684054ae39SJames Wright       }
10694054ae39SJames Wright       PetscCheck(start >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Could not find face %" PetscInt_FMT " in cone of its support", face);
10704054ae39SJames Wright       PetscCall(DMPlexGetConeOrientation(dm, cells[0], &orients));
10714054ae39SJames Wright       if (orients[start] < 0) flip = -1;
10724054ae39SJames Wright     }
10734054ae39SJames Wright 
10746ff49feeSJames Wright     // Cannot use DMPlexComputeCellGeometryFVM() for high-order geometry, so must calculate normal vectors manually
10756ff49feeSJames Wright     // Use the vertices (depth 0) of coordinate DM to calculate normal vector
1076*44a422c4SJames Wright     PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
10774054ae39SJames Wright     switch (dim) {
10784054ae39SJames Wright     case 2: {
10796ff49feeSJames Wright       PetscScalar vec[2];
10806ff49feeSJames Wright 
10816ff49feeSJames Wright       for (PetscInt d = 0; d < dim; ++d) vec[d] = flip * (PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]));
10826ff49feeSJames Wright       PetscScalar normal[] = {vec[1], -vec[0]};
10836ff49feeSJames Wright       if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) {
10846ff49feeSJames Wright         label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft;
10854054ae39SJames Wright       } else {
10866ff49feeSJames Wright         label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerTop : faceMarkerBottom;
10874054ae39SJames Wright       }
10884054ae39SJames Wright     } break;
10894054ae39SJames Wright     case 3: {
10906ff49feeSJames Wright       PetscScalar vec1[3], vec2[3], normal[3];
10916ff49feeSJames Wright 
10926ff49feeSJames Wright       for (PetscInt d = 0; d < dim; ++d) {
10936ff49feeSJames Wright         vec1[d] = PetscRealPart(coords[1 * dim + d]) - PetscRealPart(coords[0 * dim + d]);
10946ff49feeSJames Wright         vec2[d] = PetscRealPart(coords[2 * dim + d]) - PetscRealPart(coords[1 * dim + d]);
10956ff49feeSJames Wright       }
10966ff49feeSJames Wright 
10976ff49feeSJames Wright       // Calculate normal vector via cross-product
10986ff49feeSJames Wright       normal[0] = flip * ((vec1[1] * vec2[2]) - (vec1[2] * vec2[1]));
10996ff49feeSJames Wright       normal[1] = flip * ((vec1[2] * vec2[0]) - (vec1[0] * vec2[2]));
11006ff49feeSJames Wright       normal[2] = flip * ((vec1[0] * vec2[1]) - (vec1[1] * vec2[0]));
11016ff49feeSJames Wright 
11026ff49feeSJames Wright       if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[1])) {
11036ff49feeSJames Wright         if (PetscAbsScalar(normal[0]) > PetscAbsScalar(normal[2])) {
11046ff49feeSJames Wright           label_value = PetscRealPart(normal[0]) > 0 ? faceMarkerRight : faceMarkerLeft;
11054054ae39SJames Wright         } else {
11066ff49feeSJames Wright           label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom;
11074054ae39SJames Wright         }
11084054ae39SJames Wright       } else {
11096ff49feeSJames Wright         if (PetscAbsScalar(normal[1]) > PetscAbsScalar(normal[2])) {
11106ff49feeSJames Wright           label_value = PetscRealPart(normal[1]) > 0 ? faceMarkerBack : faceMarkerFront;
11114054ae39SJames Wright         } else {
11126ff49feeSJames Wright           label_value = PetscRealPart(normal[2]) > 0 ? faceMarkerTop : faceMarkerBottom;
11134054ae39SJames Wright         }
11144054ae39SJames Wright       }
11154054ae39SJames Wright     } break;
11164054ae39SJames Wright     }
11174054ae39SJames Wright 
11184054ae39SJames Wright     PetscInt previous_label_value; // always 1 due to DMPlexMarkBoundaryFaces call above
11194054ae39SJames Wright     PetscCall(DMGetLabelValue(dm, "Face Sets", face, &previous_label_value));
11204054ae39SJames Wright     PetscCall(DMClearLabelValue(dm, "Face Sets", face, previous_label_value));
11214054ae39SJames Wright     PetscCall(DMSetLabelValue(dm, "Face Sets", face, label_value));
11226ff49feeSJames Wright     PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
11234054ae39SJames Wright   }
11242b4f33d9SJames Wright   if (faces_is) PetscCall(ISRestoreIndices(faces_is, &faces));
11256ff49feeSJames Wright   PetscCall(ISDestroy(&faces_is));
1126d7d2d1d2SJames Wright 
1127d7d2d1d2SJames Wright   // Create Isoperiodic SF from newly-created face labels
1128d7d2d1d2SJames Wright   PetscSF     periodicsfs[3];
1129d7d2d1d2SJames Wright   PetscInt    periodic_sf_index  = 0;
1130d7d2d1d2SJames Wright   PetscScalar transform[3][4][4] = {{{0.}}};
1131d7d2d1d2SJames Wright   for (PetscInt d = 0; d < dim; d++) {
1132d7d2d1d2SJames Wright     IS              donor_is, periodic_is;
1133d7d2d1d2SJames Wright     const PetscInt *donor_faces = NULL, *periodic_faces = NULL;
1134d7d2d1d2SJames Wright     PetscInt        num_donor = 0, num_periodic = 0;
1135d7d2d1d2SJames Wright     PetscSF         centroidsf;
1136d7d2d1d2SJames Wright     PetscReal       donor_to_periodic_distance;
1137d7d2d1d2SJames Wright     const PetscInt  face_pairings[2][3][2] = {
1138d7d2d1d2SJames Wright       // 2D face pairings, {donor, periodic}
1139d7d2d1d2SJames Wright       {{4, 2}, {1, 3}},
1140d7d2d1d2SJames Wright       // 3D face pairings
1141d7d2d1d2SJames Wright       {{5, 6}, {3, 4}, {1, 2}}
1142d7d2d1d2SJames Wright     };
1143d7d2d1d2SJames Wright 
1144d7d2d1d2SJames Wright     if (periodicity[d] != DM_BOUNDARY_PERIODIC) continue;
1145d7d2d1d2SJames Wright     {
1146d7d2d1d2SJames Wright       // Compute centroidsf, which is the mapping from donor faces to periodic faces
1147d7d2d1d2SJames Wright       // Matches the centroid of the faces together, ignoring the periodic direction component (which should not match between donor and periodic face)
1148d7d2d1d2SJames Wright       PetscInt     coords_size, centroid_comps = dim - 1;
1149d7d2d1d2SJames Wright       PetscScalar *coords = NULL;
1150d7d2d1d2SJames Wright       PetscReal   *donor_centroids, *periodic_centroids;
1151d7d2d1d2SJames Wright       PetscReal    loc_periodic[2] = {PETSC_MIN_REAL, PETSC_MIN_REAL}, loc_periodic_global[2]; // Location of donor (0) and periodic (1) faces in periodic direction
1152d7d2d1d2SJames Wright 
1153d7d2d1d2SJames Wright       PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][0], &donor_is));
1154d7d2d1d2SJames Wright       PetscCall(DMGetStratumIS(dm, "Face Sets", face_pairings[dim - 2][d][1], &periodic_is));
1155d7d2d1d2SJames Wright       if (donor_is) {
1156d7d2d1d2SJames Wright         PetscCall(ISGetLocalSize(donor_is, &num_donor));
1157d7d2d1d2SJames Wright         PetscCall(ISGetIndices(donor_is, &donor_faces));
1158d7d2d1d2SJames Wright       }
1159d7d2d1d2SJames Wright       if (periodic_is) {
1160d7d2d1d2SJames Wright         PetscCall(ISGetLocalSize(periodic_is, &num_periodic));
1161d7d2d1d2SJames Wright         PetscCall(ISGetIndices(periodic_is, &periodic_faces));
1162d7d2d1d2SJames Wright       }
1163d7d2d1d2SJames Wright       PetscCall(PetscCalloc2(num_donor * centroid_comps, &donor_centroids, num_periodic * centroid_comps, &periodic_centroids));
1164d7d2d1d2SJames Wright       for (PetscInt f = 0; f < num_donor; f++) {
1165d7d2d1d2SJames Wright         PetscInt face = donor_faces[f], num_coords;
1166*44a422c4SJames Wright         PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
1167d7d2d1d2SJames Wright         num_coords = coords_size / dim;
1168d7d2d1d2SJames Wright         for (PetscInt c = 0; c < num_coords; c++) {
1169d7d2d1d2SJames Wright           PetscInt comp_index = 0;
1170d7d2d1d2SJames Wright           loc_periodic[0]     = PetscRealPart(coords[c * dim + d]);
1171d7d2d1d2SJames Wright           for (PetscInt i = 0; i < dim; i++) {
1172d7d2d1d2SJames Wright             if (i == d) continue; // Periodic direction not used for centroid calculation
1173d7d2d1d2SJames Wright             donor_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords;
1174d7d2d1d2SJames Wright             comp_index++;
1175d7d2d1d2SJames Wright           }
1176d7d2d1d2SJames Wright         }
1177d7d2d1d2SJames Wright         PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
1178d7d2d1d2SJames Wright       }
1179d7d2d1d2SJames Wright 
1180d7d2d1d2SJames Wright       for (PetscInt f = 0; f < num_periodic; f++) {
1181d7d2d1d2SJames Wright         PetscInt face = periodic_faces[f], num_coords;
1182*44a422c4SJames Wright         PetscCall(DMPlexVecGetClosureAtDepth(cdm, csection, coordinates, face, 0, &coords_size, &coords));
1183d7d2d1d2SJames Wright         num_coords = coords_size / dim;
1184d7d2d1d2SJames Wright         for (PetscInt c = 0; c < num_coords; c++) {
1185d7d2d1d2SJames Wright           PetscInt comp_index = 0;
1186d7d2d1d2SJames Wright           loc_periodic[1]     = PetscRealPart(coords[c * dim + d]);
1187d7d2d1d2SJames Wright           for (PetscInt i = 0; i < dim; i++) {
1188d7d2d1d2SJames Wright             if (i == d) continue; // Periodic direction not used for centroid calculation
1189d7d2d1d2SJames Wright             periodic_centroids[f * centroid_comps + comp_index] += PetscRealPart(coords[c * dim + i]) / num_coords;
1190d7d2d1d2SJames Wright             comp_index++;
1191d7d2d1d2SJames Wright           }
1192d7d2d1d2SJames Wright         }
1193d7d2d1d2SJames Wright         PetscCall(DMPlexVecRestoreClosure(cdm, csection, coordinates, face, &coords_size, &coords));
1194d7d2d1d2SJames Wright       }
1195d7d2d1d2SJames Wright       PetscCallMPI(MPIU_Allreduce(loc_periodic, loc_periodic_global, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm)));
1196d7d2d1d2SJames Wright       donor_to_periodic_distance = loc_periodic_global[1] - loc_periodic_global[0];
1197d7d2d1d2SJames Wright 
1198d7d2d1d2SJames Wright       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &centroidsf));
1199d7d2d1d2SJames Wright       PetscCall(PetscSFSetGraphFromCoordinates(centroidsf, num_donor, num_periodic, centroid_comps, 1e-10, donor_centroids, periodic_centroids));
1200d7d2d1d2SJames Wright       PetscCall(PetscSFViewFromOptions(centroidsf, NULL, "-dm_plex_box_label_centroid_sf_view"));
1201d7d2d1d2SJames Wright       PetscCall(PetscFree2(donor_centroids, periodic_centroids));
1202d7d2d1d2SJames Wright     }
1203d7d2d1d2SJames Wright 
1204d7d2d1d2SJames Wright     { // Create Isoperiodic SF using centroidsSF
1205d7d2d1d2SJames Wright       PetscInt           pStart, pEnd;
1206d7d2d1d2SJames Wright       PetscInt          *leaf_faces;
1207d7d2d1d2SJames Wright       const PetscSFNode *firemote;
1208d7d2d1d2SJames Wright       PetscSFNode       *isoperiodic_leaves;
1209d7d2d1d2SJames Wright 
1210d7d2d1d2SJames Wright       PetscCall(PetscMalloc1(num_periodic, &leaf_faces));
1211d7d2d1d2SJames Wright       PetscCall(PetscSFBcastBegin(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE));
1212d7d2d1d2SJames Wright       PetscCall(PetscSFBcastEnd(centroidsf, MPIU_INT, donor_faces, leaf_faces, MPI_REPLACE));
1213d7d2d1d2SJames Wright 
1214d7d2d1d2SJames Wright       PetscCall(PetscMalloc1(num_periodic, &isoperiodic_leaves));
1215d7d2d1d2SJames Wright       PetscCall(PetscSFGetGraph(centroidsf, NULL, NULL, NULL, &firemote));
1216d7d2d1d2SJames Wright       for (PetscInt l = 0; l < num_periodic; ++l) {
1217d7d2d1d2SJames Wright         isoperiodic_leaves[l].index = leaf_faces[l];
1218d7d2d1d2SJames Wright         isoperiodic_leaves[l].rank  = firemote[l].rank;
1219d7d2d1d2SJames Wright       }
1220d7d2d1d2SJames Wright 
1221d7d2d1d2SJames Wright       PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1222d7d2d1d2SJames Wright       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &periodicsfs[periodic_sf_index]));
1223d7d2d1d2SJames Wright       PetscCall(PetscSFSetGraph(periodicsfs[periodic_sf_index], pEnd - pStart, num_periodic, (PetscInt *)periodic_faces, PETSC_COPY_VALUES, isoperiodic_leaves, PETSC_OWN_POINTER));
1224d7d2d1d2SJames Wright       PetscCall(PetscSFViewFromOptions(periodicsfs[periodic_sf_index], NULL, "-dm_plex_box_label_periodic_sf_view"));
1225d7d2d1d2SJames Wright       PetscCall(PetscFree(leaf_faces));
1226d7d2d1d2SJames Wright     }
1227d7d2d1d2SJames Wright 
1228d7d2d1d2SJames Wright     transform[periodic_sf_index][0][0] = 1;
1229d7d2d1d2SJames Wright     transform[periodic_sf_index][1][1] = 1;
1230d7d2d1d2SJames Wright     transform[periodic_sf_index][2][2] = 1;
1231d7d2d1d2SJames Wright     transform[periodic_sf_index][3][3] = 1;
1232d7d2d1d2SJames Wright     transform[periodic_sf_index][d][3] = donor_to_periodic_distance;
1233d7d2d1d2SJames Wright 
1234d7d2d1d2SJames Wright     periodic_sf_index++;
1235d7d2d1d2SJames Wright     PetscCall(PetscSFDestroy(&centroidsf));
1236d7d2d1d2SJames Wright     if (donor_is) {
1237d7d2d1d2SJames Wright       PetscCall(ISRestoreIndices(donor_is, &donor_faces));
1238d7d2d1d2SJames Wright       PetscCall(ISDestroy(&donor_is));
1239d7d2d1d2SJames Wright     }
1240d7d2d1d2SJames Wright     if (periodic_is) {
1241d7d2d1d2SJames Wright       PetscCall(ISRestoreIndices(periodic_is, &periodic_faces));
1242d7d2d1d2SJames Wright       PetscCall(ISDestroy(&periodic_is));
1243d7d2d1d2SJames Wright     }
1244d7d2d1d2SJames Wright     PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][0]));
1245d7d2d1d2SJames Wright     PetscCall(DMClearLabelStratum(dm, "Face Sets", face_pairings[dim - 2][d][1]));
1246d7d2d1d2SJames Wright   }
1247d7d2d1d2SJames Wright   PetscCall(DMPlexSetIsoperiodicFaceSF(dm, periodic_sf_index, periodicsfs));
1248d7d2d1d2SJames Wright   PetscCall(DMPlexSetIsoperiodicFaceTransform(dm, periodic_sf_index, (const PetscScalar *)transform));
1249d7d2d1d2SJames Wright   for (PetscInt p = 0; p < periodic_sf_index; p++) PetscCall(PetscSFDestroy(&periodicsfs[p]));
1250d7d2d1d2SJames Wright 
1251d7d2d1d2SJames Wright   { // Update coordinate DM with new Face Sets label
1252d7d2d1d2SJames Wright     DM      cdm;
1253d7d2d1d2SJames Wright     DMLabel oldFaceSets, newFaceSets;
1254d7d2d1d2SJames Wright     PetscCall(DMGetCoordinateDM(dm, &cdm));
1255d7d2d1d2SJames Wright     PetscCall(DMGetLabel(cdm, "Face Sets", &oldFaceSets));
1256d7d2d1d2SJames Wright     if (oldFaceSets) PetscCall(DMRemoveLabelBySelf(cdm, &oldFaceSets, PETSC_FALSE));
1257d7d2d1d2SJames Wright     PetscCall(DMLabelDuplicate(label, &newFaceSets));
1258d7d2d1d2SJames Wright     PetscCall(DMAddLabel(cdm, newFaceSets));
1259d7d2d1d2SJames Wright     PetscCall(DMLabelDestroy(&newFaceSets));
1260d7d2d1d2SJames Wright   }
12614054ae39SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
12624054ae39SJames Wright }
12634054ae39SJames Wright 
1264d698cf03SStefano Zampini static PetscErrorCode DMPlexCreateSquareMesh_Simplex_CrissCross(DM dm, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType bd[])
1265d698cf03SStefano Zampini {
1266d698cf03SStefano Zampini   PetscInt       markerTop = 1, faceMarkerTop = 3;
1267d698cf03SStefano Zampini   PetscInt       markerBottom = 1, faceMarkerBottom = 1;
1268d698cf03SStefano Zampini   PetscInt       markerRight = 1, faceMarkerRight = 2;
1269d698cf03SStefano Zampini   PetscInt       markerLeft = 1, faceMarkerLeft = 4;
1270d698cf03SStefano Zampini   PetscBool      markerSeparate = PETSC_FALSE;
1271d698cf03SStefano Zampini   DMBoundaryType bdX = bd[0], bdY = bd[1];
1272d698cf03SStefano Zampini   PetscMPIInt    rank;
1273d698cf03SStefano Zampini 
1274d698cf03SStefano Zampini   PetscFunctionBegin;
1275d698cf03SStefano Zampini   PetscCheck(bdX == DM_BOUNDARY_NONE || bdX == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdX]);
1276d698cf03SStefano Zampini   PetscCheck(bdY == DM_BOUNDARY_NONE || bdY == DM_BOUNDARY_PERIODIC, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not implemented for boundary type %s", DMBoundaryTypes[bdY]);
1277d698cf03SStefano Zampini   PetscCall(DMSetDimension(dm, 2));
1278d698cf03SStefano Zampini   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1279d698cf03SStefano Zampini   PetscCall(DMCreateLabel(dm, "marker"));
1280d698cf03SStefano Zampini   PetscCall(DMCreateLabel(dm, "Face Sets"));
1281d698cf03SStefano Zampini   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
1282d698cf03SStefano Zampini   if (markerSeparate) {
1283d698cf03SStefano Zampini     markerBottom = faceMarkerBottom;
1284d698cf03SStefano Zampini     markerTop    = faceMarkerTop;
1285d698cf03SStefano Zampini     markerRight  = faceMarkerRight;
1286d698cf03SStefano Zampini     markerLeft   = faceMarkerLeft;
1287d698cf03SStefano Zampini   }
1288d698cf03SStefano Zampini   {
1289d698cf03SStefano Zampini     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
1290d698cf03SStefano Zampini     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
1291d698cf03SStefano Zampini     const PetscInt numZEdges    = rank == 0 ? 4 * edges[0] * edges[1] : 0; /* Z-edges are the 4 internal edges per cell */
1292d698cf03SStefano Zampini     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC ? edges[0] : edges[0] + 1) : 0;
1293d698cf03SStefano Zampini     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC ? edges[1] : edges[1] + 1) : 0;
1294d698cf03SStefano Zampini     const PetscInt numZVertices = rank == 0 ? edges[0] * edges[1] : 0;
1295d698cf03SStefano Zampini     const PetscInt numCells     = 4 * numXEdges * numYEdges;
1296d698cf03SStefano Zampini     const PetscInt numTotXEdges = numXEdges * numYVertices;
1297d698cf03SStefano Zampini     const PetscInt numTotYEdges = numYEdges * numXVertices;
1298d698cf03SStefano Zampini     const PetscInt numVertices  = numXVertices * numYVertices + numZVertices;
1299d698cf03SStefano Zampini     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numZEdges;
1300d698cf03SStefano Zampini     const PetscInt firstVertex  = numCells;
1301d698cf03SStefano Zampini     const PetscInt firstXEdge   = numCells + numVertices;
1302d698cf03SStefano Zampini     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
1303d698cf03SStefano Zampini     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
1304d698cf03SStefano Zampini     Vec            coordinates;
1305d698cf03SStefano Zampini     PetscSection   coordSection;
1306d698cf03SStefano Zampini     PetscScalar   *coords;
1307d698cf03SStefano Zampini     PetscInt       coordSize;
1308d698cf03SStefano Zampini     PetscInt       v, vx, vy;
1309d698cf03SStefano Zampini     PetscInt       c, e, ex, ey;
1310d698cf03SStefano Zampini 
1311d698cf03SStefano Zampini     PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVertices));
1312d698cf03SStefano Zampini     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 3));
1313d698cf03SStefano Zampini     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
1314d698cf03SStefano Zampini     PetscCall(DMSetUp(dm));
1315d698cf03SStefano Zampini 
1316d698cf03SStefano Zampini     /* Build cells and Z-edges */
1317d698cf03SStefano Zampini     for (ey = 0; ey < numYEdges; ++ey) {
1318d698cf03SStefano Zampini       for (ex = 0; ex < numXEdges; ++ex) {
1319d698cf03SStefano Zampini         const PetscInt exp1 = (ex + 1) % numXVertices;
1320d698cf03SStefano Zampini         const PetscInt eyp1 = (ey + 1) % numYVertices;
1321d698cf03SStefano Zampini         const PetscInt ez   = firstZEdge + 4 * (ey * numXEdges + ex);
1322d698cf03SStefano Zampini         const PetscInt vc   = firstVertex + numXVertices * numYVertices + ey * numXEdges + ex;
1323d698cf03SStefano Zampini         const PetscInt v0   = firstVertex + ey * numXVertices + ex;
1324d698cf03SStefano Zampini         const PetscInt v1   = firstVertex + ey * numXVertices + exp1;
1325d698cf03SStefano Zampini         const PetscInt v2   = firstVertex + eyp1 * numXVertices + exp1;
1326d698cf03SStefano Zampini         const PetscInt v3   = firstVertex + eyp1 * numXVertices + ex;
1327d698cf03SStefano Zampini         const PetscInt e0   = firstXEdge + ey * numXEdges + ex;
1328d698cf03SStefano Zampini         const PetscInt e1   = firstYEdge + exp1 * numYEdges + ey;
1329d698cf03SStefano Zampini         const PetscInt e2   = firstXEdge + eyp1 * numXEdges + ex;
1330d698cf03SStefano Zampini         const PetscInt e3   = firstYEdge + ex * numYEdges + ey;
1331d698cf03SStefano Zampini 
1332d698cf03SStefano Zampini         const PetscInt cones[] = {ez, e0, ez + 1, ez + 1, e1, ez + 2, ez + 2, e2, ez + 3, ez + 3, e3, ez};
1333d698cf03SStefano Zampini         const PetscInt ornts[] = {-1, 0, 0, -1, 0, 0, -1, -1, 0, -1, -1, 0};
1334d698cf03SStefano Zampini         const PetscInt verts[] = {v0, vc, v1, vc, v2, vc, v3, vc};
1335d698cf03SStefano Zampini 
1336d698cf03SStefano Zampini         for (c = 0; c < 4; c++) {
1337d698cf03SStefano Zampini           PetscInt cell = 4 * (ey * numXEdges + ex) + c;
1338d698cf03SStefano Zampini           PetscInt edge = ez + c;
1339d698cf03SStefano Zampini 
1340d698cf03SStefano Zampini           PetscCall(DMPlexSetCone(dm, cell, cones + 3 * c));
1341d698cf03SStefano Zampini           PetscCall(DMPlexSetConeOrientation(dm, cell, ornts + 3 * c));
1342d698cf03SStefano Zampini           PetscCall(DMPlexSetCone(dm, edge, verts + 2 * c));
1343d698cf03SStefano Zampini         }
1344d698cf03SStefano Zampini       }
1345d698cf03SStefano Zampini     }
1346d698cf03SStefano Zampini 
1347d698cf03SStefano Zampini     /* Build Y edges*/
1348d698cf03SStefano Zampini     for (vx = 0; vx < numXVertices; vx++) {
1349d698cf03SStefano Zampini       for (ey = 0; ey < numYEdges; ey++) {
1350d698cf03SStefano Zampini         const PetscInt edge   = firstYEdge + vx * numYEdges + ey;
1351d698cf03SStefano Zampini         const PetscInt v0     = firstVertex + ey * numXVertices + vx;
1352d698cf03SStefano Zampini         const PetscInt v1     = firstVertex + ((ey + 1) % numYVertices) * numXVertices + vx;
1353d698cf03SStefano Zampini         const PetscInt cone[] = {v0, v1};
1354d698cf03SStefano Zampini 
1355d698cf03SStefano Zampini         PetscCall(DMPlexSetCone(dm, edge, cone));
1356d698cf03SStefano Zampini         if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
1357d698cf03SStefano Zampini           if (vx == numXVertices - 1) {
1358d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
1359d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1360d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1361d698cf03SStefano Zampini             if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1362d698cf03SStefano Zampini           } else if (vx == 0) {
1363d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
1364d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1365d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1366d698cf03SStefano Zampini             if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
1367d698cf03SStefano Zampini           }
1368d698cf03SStefano Zampini         }
1369d698cf03SStefano Zampini       }
1370d698cf03SStefano Zampini     }
1371d698cf03SStefano Zampini 
1372d698cf03SStefano Zampini     /* Build X edges*/
1373d698cf03SStefano Zampini     for (vy = 0; vy < numYVertices; vy++) {
1374d698cf03SStefano Zampini       for (ex = 0; ex < numXEdges; ex++) {
1375d698cf03SStefano Zampini         const PetscInt edge   = firstXEdge + vy * numXEdges + ex;
1376d698cf03SStefano Zampini         const PetscInt v0     = firstVertex + vy * numXVertices + ex;
1377d698cf03SStefano Zampini         const PetscInt v1     = firstVertex + vy * numXVertices + (ex + 1) % numXVertices;
1378d698cf03SStefano Zampini         const PetscInt cone[] = {v0, v1};
1379d698cf03SStefano Zampini 
1380d698cf03SStefano Zampini         PetscCall(DMPlexSetCone(dm, edge, cone));
1381d698cf03SStefano Zampini         if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
1382d698cf03SStefano Zampini           if (vy == numYVertices - 1) {
1383d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
1384d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1385d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1386d698cf03SStefano Zampini             if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1387d698cf03SStefano Zampini           } else if (vy == 0) {
1388d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
1389d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1390d698cf03SStefano Zampini             PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1391d698cf03SStefano Zampini             if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
1392d698cf03SStefano Zampini           }
1393d698cf03SStefano Zampini         }
1394d698cf03SStefano Zampini       }
1395d698cf03SStefano Zampini     }
1396d698cf03SStefano Zampini 
1397d698cf03SStefano Zampini     /* Compute support, stratify, and celltype label */
1398d698cf03SStefano Zampini     PetscCall(DMPlexSymmetrize(dm));
1399d698cf03SStefano Zampini     PetscCall(DMPlexStratify(dm));
1400d698cf03SStefano Zampini     PetscCall(DMPlexComputeCellTypes(dm));
1401d698cf03SStefano Zampini 
1402d698cf03SStefano Zampini     /* Build coordinates */
1403d698cf03SStefano Zampini     PetscCall(DMGetCoordinateSection(dm, &coordSection));
1404d698cf03SStefano Zampini     PetscCall(PetscSectionSetNumFields(coordSection, 1));
1405d698cf03SStefano Zampini     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 2));
1406d698cf03SStefano Zampini     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
1407d698cf03SStefano Zampini     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
1408d698cf03SStefano Zampini       PetscCall(PetscSectionSetDof(coordSection, v, 2));
1409d698cf03SStefano Zampini       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 2));
1410d698cf03SStefano Zampini     }
1411d698cf03SStefano Zampini     PetscCall(PetscSectionSetUp(coordSection));
1412d698cf03SStefano Zampini     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
1413d698cf03SStefano Zampini     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
1414d698cf03SStefano Zampini     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
1415d698cf03SStefano Zampini     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
1416d698cf03SStefano Zampini     PetscCall(VecSetBlockSize(coordinates, 2));
1417d698cf03SStefano Zampini     PetscCall(VecSetType(coordinates, VECSTANDARD));
1418d698cf03SStefano Zampini     PetscCall(VecGetArray(coordinates, &coords));
1419d698cf03SStefano Zampini     for (vy = 0; vy < numYVertices; ++vy) {
1420d698cf03SStefano Zampini       for (vx = 0; vx < numXVertices; ++vx) {
1421d698cf03SStefano Zampini         coords[2 * (vy * numXVertices + vx) + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
1422d698cf03SStefano Zampini         coords[2 * (vy * numXVertices + vx) + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1423d698cf03SStefano Zampini       }
1424d698cf03SStefano Zampini     }
1425d698cf03SStefano Zampini     for (ey = 0; ey < numYEdges; ++ey) {
1426d698cf03SStefano Zampini       for (ex = 0; ex < numXEdges; ++ex) {
1427d698cf03SStefano Zampini         const PetscInt c = ey * numXEdges + ex + numYVertices * numXVertices;
1428d698cf03SStefano Zampini 
1429d698cf03SStefano Zampini         coords[2 * c + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * (ex + 0.5);
1430d698cf03SStefano Zampini         coords[2 * c + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * (ey + 0.5);
1431d698cf03SStefano Zampini       }
1432d698cf03SStefano Zampini     }
1433d698cf03SStefano Zampini     PetscCall(VecRestoreArray(coordinates, &coords));
1434d698cf03SStefano Zampini     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
1435d698cf03SStefano Zampini     PetscCall(VecDestroy(&coordinates));
1436d698cf03SStefano Zampini 
1437d698cf03SStefano Zampini     /* handle periodic BC */
1438d698cf03SStefano Zampini     if (bdX == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_PERIODIC) {
1439d698cf03SStefano Zampini       PetscReal L[2]       = {-1., -1.};
1440d698cf03SStefano Zampini       PetscReal maxCell[2] = {-1., -1.};
1441d698cf03SStefano Zampini 
1442d698cf03SStefano Zampini       for (PetscInt d = 0; d < 2; ++d) {
1443d698cf03SStefano Zampini         if (bd[d] != DM_BOUNDARY_NONE) {
1444d698cf03SStefano Zampini           L[d]       = upper[d] - lower[d];
1445d698cf03SStefano Zampini           maxCell[d] = 1.1 * (L[d] / PetscMax(1, edges[d]));
1446d698cf03SStefano Zampini         }
1447d698cf03SStefano Zampini       }
1448d698cf03SStefano Zampini       PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1449d698cf03SStefano Zampini     }
1450d698cf03SStefano Zampini   }
1451d698cf03SStefano Zampini   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
1452d698cf03SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
1453d698cf03SStefano Zampini }
1454d698cf03SStefano Zampini 
1455d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxMesh_Simplex_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1456d71ae5a4SJacob Faibussowitsch {
14579318fe57SMatthew G. Knepley   DM        boundary, vol;
1458c22d3578SMatthew G. Knepley   DMLabel   bdlabel;
1459d698cf03SStefano Zampini   PetscBool crisscross = PETSC_FALSE;
1460d6218766SMatthew G. Knepley 
1461d6218766SMatthew G. Knepley   PetscFunctionBegin;
14624f572ea9SToby Isaac   PetscAssertPointer(dm, 1);
1463d698cf03SStefano Zampini   if (dim == 2) PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_box_crisscross", &crisscross, NULL));
1464d698cf03SStefano Zampini   if (crisscross) {
1465d698cf03SStefano Zampini     PetscCall(DMPlexCreateSquareMesh_Simplex_CrissCross(dm, faces, lower, upper, periodicity));
1466d698cf03SStefano Zampini   } else {
1467c22d3578SMatthew G. Knepley     for (PetscInt i = 0; i < dim; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity is not supported for simplex meshes");
14689566063dSJacob Faibussowitsch     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &boundary));
14699566063dSJacob Faibussowitsch     PetscCall(DMSetType(boundary, DMPLEX));
1470d698cf03SStefano Zampini     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)boundary, ((PetscObject)dm)->prefix));
14719566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(boundary, dim, faces, lower, upper, PETSC_FALSE));
14729566063dSJacob Faibussowitsch     PetscCall(DMPlexGenerate(boundary, NULL, interpolate, &vol));
1473c22d3578SMatthew G. Knepley     PetscCall(DMGetLabel(vol, "marker", &bdlabel));
1474c22d3578SMatthew G. Knepley     if (bdlabel) PetscCall(DMPlexLabelComplete(vol, bdlabel));
14755de52c6dSVaclav Hapla     PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_FALSE, vol));
147669d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &vol));
1477d698cf03SStefano Zampini     PetscCall(DMDestroy(&boundary));
1478d698cf03SStefano Zampini   }
14794054ae39SJames Wright   if (interpolate) {
14804054ae39SJames Wright     PetscCall(DMPlexInterpolateInPlace_Internal(dm));
1481d7d2d1d2SJames Wright     PetscCall(DMPlexSetBoxLabel_Internal(dm, periodicity));
14824054ae39SJames Wright   }
14833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1484d6218766SMatthew G. Knepley }
1485d6218766SMatthew G. Knepley 
1486d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateCubeMesh_Internal(DM dm, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], DMBoundaryType bdX, DMBoundaryType bdY, DMBoundaryType bdZ)
1487d71ae5a4SJacob Faibussowitsch {
1488ed0e4b50SMatthew G. Knepley   DMLabel     cutLabel  = NULL;
1489f4eb4c5dSMatthew G. Knepley   PetscInt    markerTop = 1, faceMarkerTop = 1;
1490f4eb4c5dSMatthew G. Knepley   PetscInt    markerBottom = 1, faceMarkerBottom = 1;
1491f4eb4c5dSMatthew G. Knepley   PetscInt    markerFront = 1, faceMarkerFront = 1;
1492f4eb4c5dSMatthew G. Knepley   PetscInt    markerBack = 1, faceMarkerBack = 1;
1493f4eb4c5dSMatthew G. Knepley   PetscInt    markerRight = 1, faceMarkerRight = 1;
1494f4eb4c5dSMatthew G. Knepley   PetscInt    markerLeft = 1, faceMarkerLeft = 1;
14953dfda0b1SToby Isaac   PetscInt    dim;
1496d8211ee3SMatthew G. Knepley   PetscBool   markerSeparate = PETSC_FALSE, cutMarker = PETSC_FALSE;
14973dfda0b1SToby Isaac   PetscMPIInt rank;
14983dfda0b1SToby Isaac 
14993dfda0b1SToby Isaac   PetscFunctionBegin;
15009566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
15019566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
15029566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "marker"));
15039566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "Face Sets"));
15049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
15059371c9d4SSatish Balay   if (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST || bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST || bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST) {
15069371c9d4SSatish Balay     if (cutMarker) {
15079371c9d4SSatish Balay       PetscCall(DMCreateLabel(dm, "periodic_cut"));
15089371c9d4SSatish Balay       PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
15099371c9d4SSatish Balay     }
1510d8211ee3SMatthew G. Knepley   }
15113dfda0b1SToby Isaac   switch (dim) {
15123dfda0b1SToby Isaac   case 2:
1513f4eb4c5dSMatthew G. Knepley     faceMarkerTop    = 3;
1514f4eb4c5dSMatthew G. Knepley     faceMarkerBottom = 1;
1515f4eb4c5dSMatthew G. Knepley     faceMarkerRight  = 2;
1516f4eb4c5dSMatthew G. Knepley     faceMarkerLeft   = 4;
15173dfda0b1SToby Isaac     break;
15183dfda0b1SToby Isaac   case 3:
1519f4eb4c5dSMatthew G. Knepley     faceMarkerBottom = 1;
1520f4eb4c5dSMatthew G. Knepley     faceMarkerTop    = 2;
1521f4eb4c5dSMatthew G. Knepley     faceMarkerFront  = 3;
1522f4eb4c5dSMatthew G. Knepley     faceMarkerBack   = 4;
1523f4eb4c5dSMatthew G. Knepley     faceMarkerRight  = 5;
1524f4eb4c5dSMatthew G. Knepley     faceMarkerLeft   = 6;
15253dfda0b1SToby Isaac     break;
1526d71ae5a4SJacob Faibussowitsch   default:
1527d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", dim);
15283dfda0b1SToby Isaac   }
15299566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_separate_marker", &markerSeparate, NULL));
1530f4eb4c5dSMatthew G. Knepley   if (markerSeparate) {
1531f4eb4c5dSMatthew G. Knepley     markerBottom = faceMarkerBottom;
1532f4eb4c5dSMatthew G. Knepley     markerTop    = faceMarkerTop;
1533f4eb4c5dSMatthew G. Knepley     markerFront  = faceMarkerFront;
1534f4eb4c5dSMatthew G. Knepley     markerBack   = faceMarkerBack;
1535f4eb4c5dSMatthew G. Knepley     markerRight  = faceMarkerRight;
1536f4eb4c5dSMatthew G. Knepley     markerLeft   = faceMarkerLeft;
15373dfda0b1SToby Isaac   }
15383dfda0b1SToby Isaac   {
1539dd400576SPatrick Sanan     const PetscInt numXEdges    = rank == 0 ? edges[0] : 0;
1540dd400576SPatrick Sanan     const PetscInt numYEdges    = rank == 0 ? edges[1] : 0;
1541dd400576SPatrick Sanan     const PetscInt numZEdges    = rank == 0 ? edges[2] : 0;
1542dd400576SPatrick Sanan     const PetscInt numXVertices = rank == 0 ? (bdX == DM_BOUNDARY_PERIODIC || bdX == DM_BOUNDARY_TWIST ? edges[0] : edges[0] + 1) : 0;
1543dd400576SPatrick Sanan     const PetscInt numYVertices = rank == 0 ? (bdY == DM_BOUNDARY_PERIODIC || bdY == DM_BOUNDARY_TWIST ? edges[1] : edges[1] + 1) : 0;
1544dd400576SPatrick Sanan     const PetscInt numZVertices = rank == 0 ? (bdZ == DM_BOUNDARY_PERIODIC || bdZ == DM_BOUNDARY_TWIST ? edges[2] : edges[2] + 1) : 0;
15453dfda0b1SToby Isaac     const PetscInt numCells     = numXEdges * numYEdges * numZEdges;
15463dfda0b1SToby Isaac     const PetscInt numXFaces    = numYEdges * numZEdges;
15473dfda0b1SToby Isaac     const PetscInt numYFaces    = numXEdges * numZEdges;
15483dfda0b1SToby Isaac     const PetscInt numZFaces    = numXEdges * numYEdges;
15493dfda0b1SToby Isaac     const PetscInt numTotXFaces = numXVertices * numXFaces;
15503dfda0b1SToby Isaac     const PetscInt numTotYFaces = numYVertices * numYFaces;
15513dfda0b1SToby Isaac     const PetscInt numTotZFaces = numZVertices * numZFaces;
15523dfda0b1SToby Isaac     const PetscInt numFaces     = numTotXFaces + numTotYFaces + numTotZFaces;
15533dfda0b1SToby Isaac     const PetscInt numTotXEdges = numXEdges * numYVertices * numZVertices;
15543dfda0b1SToby Isaac     const PetscInt numTotYEdges = numYEdges * numXVertices * numZVertices;
15553dfda0b1SToby Isaac     const PetscInt numTotZEdges = numZEdges * numXVertices * numYVertices;
15563dfda0b1SToby Isaac     const PetscInt numVertices  = numXVertices * numYVertices * numZVertices;
15573dfda0b1SToby Isaac     const PetscInt numEdges     = numTotXEdges + numTotYEdges + numTotZEdges;
15583dfda0b1SToby Isaac     const PetscInt firstVertex  = (dim == 2) ? numFaces : numCells;
15593dfda0b1SToby Isaac     const PetscInt firstXFace   = (dim == 2) ? 0 : numCells + numVertices;
15603dfda0b1SToby Isaac     const PetscInt firstYFace   = firstXFace + numTotXFaces;
15613dfda0b1SToby Isaac     const PetscInt firstZFace   = firstYFace + numTotYFaces;
15623dfda0b1SToby Isaac     const PetscInt firstXEdge   = numCells + numFaces + numVertices;
15633dfda0b1SToby Isaac     const PetscInt firstYEdge   = firstXEdge + numTotXEdges;
15643dfda0b1SToby Isaac     const PetscInt firstZEdge   = firstYEdge + numTotYEdges;
15653dfda0b1SToby Isaac     Vec            coordinates;
15663dfda0b1SToby Isaac     PetscSection   coordSection;
15673dfda0b1SToby Isaac     PetscScalar   *coords;
15683dfda0b1SToby Isaac     PetscInt       coordSize;
15693dfda0b1SToby Isaac     PetscInt       v, vx, vy, vz;
15703dfda0b1SToby Isaac     PetscInt       c, f, fx, fy, fz, e, ex, ey, ez;
15713dfda0b1SToby Isaac 
15729566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numCells + numFaces + numEdges + numVertices));
157348a46eb9SPierre Jolivet     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
157448a46eb9SPierre Jolivet     for (f = firstXFace; f < firstXFace + numFaces; ++f) PetscCall(DMPlexSetConeSize(dm, f, 4));
157548a46eb9SPierre Jolivet     for (e = firstXEdge; e < firstXEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
15769566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm)); /* Allocate space for cones */
15773dfda0b1SToby Isaac     /* Build cells */
15783dfda0b1SToby Isaac     for (fz = 0; fz < numZEdges; ++fz) {
15793dfda0b1SToby Isaac       for (fy = 0; fy < numYEdges; ++fy) {
15803dfda0b1SToby Isaac         for (fx = 0; fx < numXEdges; ++fx) {
15813dfda0b1SToby Isaac           PetscInt cell  = (fz * numYEdges + fy) * numXEdges + fx;
15823dfda0b1SToby Isaac           PetscInt faceB = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
15833dfda0b1SToby Isaac           PetscInt faceT = firstZFace + (fy * numXEdges + fx) * numZVertices + ((fz + 1) % numZVertices);
15843dfda0b1SToby Isaac           PetscInt faceF = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
15853dfda0b1SToby Isaac           PetscInt faceK = firstYFace + (fz * numXEdges + fx) * numYVertices + ((fy + 1) % numYVertices);
15863dfda0b1SToby Isaac           PetscInt faceL = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
15873dfda0b1SToby Isaac           PetscInt faceR = firstXFace + (fz * numYEdges + fy) * numXVertices + ((fx + 1) % numXVertices);
15883dfda0b1SToby Isaac           /* B,  T,  F,  K,  R,  L */
1589b5a892a1SMatthew G. Knepley           PetscInt ornt[6] = {-2, 0, 0, -3, 0, -2}; /* ??? */
159042206facSLisandro Dalcin           PetscInt cone[6];
15913dfda0b1SToby Isaac 
15923dfda0b1SToby Isaac           /* no boundary twisting in 3D */
15939371c9d4SSatish Balay           cone[0] = faceB;
15949371c9d4SSatish Balay           cone[1] = faceT;
15959371c9d4SSatish Balay           cone[2] = faceF;
15969371c9d4SSatish Balay           cone[3] = faceK;
15979371c9d4SSatish Balay           cone[4] = faceR;
15989371c9d4SSatish Balay           cone[5] = faceL;
15999566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, cell, cone));
16009566063dSJacob Faibussowitsch           PetscCall(DMPlexSetConeOrientation(dm, cell, ornt));
16019566063dSJacob Faibussowitsch           if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
16029566063dSJacob Faibussowitsch           if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
16039566063dSJacob Faibussowitsch           if (bdZ != DM_BOUNDARY_NONE && fz == numZEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, cell, 2));
16043dfda0b1SToby Isaac         }
16053dfda0b1SToby Isaac       }
16063dfda0b1SToby Isaac     }
16073dfda0b1SToby Isaac     /* Build x faces */
16083dfda0b1SToby Isaac     for (fz = 0; fz < numZEdges; ++fz) {
16093dfda0b1SToby Isaac       for (fy = 0; fy < numYEdges; ++fy) {
16103dfda0b1SToby Isaac         for (fx = 0; fx < numXVertices; ++fx) {
16113dfda0b1SToby Isaac           PetscInt face    = firstXFace + (fz * numYEdges + fy) * numXVertices + fx;
16123dfda0b1SToby Isaac           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
16133dfda0b1SToby Isaac           PetscInt edgeR   = firstZEdge + (((fy + 1) % numYVertices) * numXVertices + fx) * numZEdges + fz;
16143dfda0b1SToby Isaac           PetscInt edgeB   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
16153dfda0b1SToby Isaac           PetscInt edgeT   = firstYEdge + (((fz + 1) % numZVertices) * numXVertices + fx) * numYEdges + fy;
1616b5a892a1SMatthew G. Knepley           PetscInt ornt[4] = {0, 0, -1, -1};
16173dfda0b1SToby Isaac           PetscInt cone[4];
16183dfda0b1SToby Isaac 
16193dfda0b1SToby Isaac           if (dim == 3) {
16203dfda0b1SToby Isaac             /* markers */
16213dfda0b1SToby Isaac             if (bdX != DM_BOUNDARY_PERIODIC) {
16223dfda0b1SToby Isaac               if (fx == numXVertices - 1) {
16239566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerRight));
16249566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerRight));
16259371c9d4SSatish Balay               } else if (fx == 0) {
16269566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerLeft));
16279566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerLeft));
16283dfda0b1SToby Isaac               }
16293dfda0b1SToby Isaac             }
16303dfda0b1SToby Isaac           }
16319371c9d4SSatish Balay           cone[0] = edgeB;
16329371c9d4SSatish Balay           cone[1] = edgeR;
16339371c9d4SSatish Balay           cone[2] = edgeT;
16349371c9d4SSatish Balay           cone[3] = edgeL;
16359566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, face, cone));
16369566063dSJacob Faibussowitsch           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
16373dfda0b1SToby Isaac         }
16383dfda0b1SToby Isaac       }
16393dfda0b1SToby Isaac     }
16403dfda0b1SToby Isaac     /* Build y faces */
16413dfda0b1SToby Isaac     for (fz = 0; fz < numZEdges; ++fz) {
164242206facSLisandro Dalcin       for (fx = 0; fx < numXEdges; ++fx) {
16433dfda0b1SToby Isaac         for (fy = 0; fy < numYVertices; ++fy) {
16443dfda0b1SToby Isaac           PetscInt face    = firstYFace + (fz * numXEdges + fx) * numYVertices + fy;
16453dfda0b1SToby Isaac           PetscInt edgeL   = firstZEdge + (fy * numXVertices + fx) * numZEdges + fz;
16463dfda0b1SToby Isaac           PetscInt edgeR   = firstZEdge + (fy * numXVertices + ((fx + 1) % numXVertices)) * numZEdges + fz;
16473dfda0b1SToby Isaac           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
16483dfda0b1SToby Isaac           PetscInt edgeT   = firstXEdge + (((fz + 1) % numZVertices) * numYVertices + fy) * numXEdges + fx;
1649b5a892a1SMatthew G. Knepley           PetscInt ornt[4] = {0, 0, -1, -1};
16503dfda0b1SToby Isaac           PetscInt cone[4];
16513dfda0b1SToby Isaac 
16523dfda0b1SToby Isaac           if (dim == 3) {
16533dfda0b1SToby Isaac             /* markers */
16543dfda0b1SToby Isaac             if (bdY != DM_BOUNDARY_PERIODIC) {
16553dfda0b1SToby Isaac               if (fy == numYVertices - 1) {
16569566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBack));
16579566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBack));
16589371c9d4SSatish Balay               } else if (fy == 0) {
16599566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerFront));
16609566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerFront));
16613dfda0b1SToby Isaac               }
16623dfda0b1SToby Isaac             }
16633dfda0b1SToby Isaac           }
16649371c9d4SSatish Balay           cone[0] = edgeB;
16659371c9d4SSatish Balay           cone[1] = edgeR;
16669371c9d4SSatish Balay           cone[2] = edgeT;
16679371c9d4SSatish Balay           cone[3] = edgeL;
16689566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, face, cone));
16699566063dSJacob Faibussowitsch           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
16703dfda0b1SToby Isaac         }
16713dfda0b1SToby Isaac       }
16723dfda0b1SToby Isaac     }
16733dfda0b1SToby Isaac     /* Build z faces */
16743dfda0b1SToby Isaac     for (fy = 0; fy < numYEdges; ++fy) {
16753dfda0b1SToby Isaac       for (fx = 0; fx < numXEdges; ++fx) {
16763dfda0b1SToby Isaac         for (fz = 0; fz < numZVertices; fz++) {
16773dfda0b1SToby Isaac           PetscInt face    = firstZFace + (fy * numXEdges + fx) * numZVertices + fz;
16783dfda0b1SToby Isaac           PetscInt edgeL   = firstYEdge + (fz * numXVertices + fx) * numYEdges + fy;
16793dfda0b1SToby Isaac           PetscInt edgeR   = firstYEdge + (fz * numXVertices + ((fx + 1) % numXVertices)) * numYEdges + fy;
16803dfda0b1SToby Isaac           PetscInt edgeB   = firstXEdge + (fz * numYVertices + fy) * numXEdges + fx;
16813dfda0b1SToby Isaac           PetscInt edgeT   = firstXEdge + (fz * numYVertices + ((fy + 1) % numYVertices)) * numXEdges + fx;
1682b5a892a1SMatthew G. Knepley           PetscInt ornt[4] = {0, 0, -1, -1};
16833dfda0b1SToby Isaac           PetscInt cone[4];
16843dfda0b1SToby Isaac 
16853dfda0b1SToby Isaac           if (dim == 2) {
16869371c9d4SSatish Balay             if (bdX == DM_BOUNDARY_TWIST && fx == numXEdges - 1) {
16879371c9d4SSatish Balay               edgeR += numYEdges - 1 - 2 * fy;
16889371c9d4SSatish Balay               ornt[1] = -1;
16899371c9d4SSatish Balay             }
16909371c9d4SSatish Balay             if (bdY == DM_BOUNDARY_TWIST && fy == numYEdges - 1) {
16919371c9d4SSatish Balay               edgeT += numXEdges - 1 - 2 * fx;
16929371c9d4SSatish Balay               ornt[2] = 0;
16939371c9d4SSatish Balay             }
16949566063dSJacob Faibussowitsch             if (bdX != DM_BOUNDARY_NONE && fx == numXEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
16959566063dSJacob Faibussowitsch             if (bdY != DM_BOUNDARY_NONE && fy == numYEdges - 1 && cutLabel) PetscCall(DMLabelSetValue(cutLabel, face, 2));
1696d1c88043SMatthew G. Knepley           } else {
16973dfda0b1SToby Isaac             /* markers */
16983dfda0b1SToby Isaac             if (bdZ != DM_BOUNDARY_PERIODIC) {
16993dfda0b1SToby Isaac               if (fz == numZVertices - 1) {
17009566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerTop));
17019566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerTop));
17029371c9d4SSatish Balay               } else if (fz == 0) {
17039566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", face, faceMarkerBottom));
17049566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", face, markerBottom));
17053dfda0b1SToby Isaac               }
17063dfda0b1SToby Isaac             }
17073dfda0b1SToby Isaac           }
17089371c9d4SSatish Balay           cone[0] = edgeB;
17099371c9d4SSatish Balay           cone[1] = edgeR;
17109371c9d4SSatish Balay           cone[2] = edgeT;
17119371c9d4SSatish Balay           cone[3] = edgeL;
17129566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, face, cone));
17139566063dSJacob Faibussowitsch           PetscCall(DMPlexSetConeOrientation(dm, face, ornt));
17143dfda0b1SToby Isaac         }
17153dfda0b1SToby Isaac       }
17163dfda0b1SToby Isaac     }
17173dfda0b1SToby Isaac     /* Build Z edges*/
17183dfda0b1SToby Isaac     for (vy = 0; vy < numYVertices; vy++) {
17193dfda0b1SToby Isaac       for (vx = 0; vx < numXVertices; vx++) {
17203dfda0b1SToby Isaac         for (ez = 0; ez < numZEdges; ez++) {
17213dfda0b1SToby Isaac           const PetscInt edge    = firstZEdge + (vy * numXVertices + vx) * numZEdges + ez;
17223dfda0b1SToby Isaac           const PetscInt vertexB = firstVertex + (ez * numYVertices + vy) * numXVertices + vx;
17233dfda0b1SToby Isaac           const PetscInt vertexT = firstVertex + (((ez + 1) % numZVertices) * numYVertices + vy) * numXVertices + vx;
17243dfda0b1SToby Isaac           PetscInt       cone[2];
17253dfda0b1SToby Isaac 
17269371c9d4SSatish Balay           cone[0] = vertexB;
17279371c9d4SSatish Balay           cone[1] = vertexT;
1728c2df9bbfSMatthew G. Knepley           PetscCall(DMPlexSetCone(dm, edge, cone));
17293dfda0b1SToby Isaac           if (dim == 3) {
17303dfda0b1SToby Isaac             if (bdX != DM_BOUNDARY_PERIODIC) {
17313dfda0b1SToby Isaac               if (vx == numXVertices - 1) {
17329566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1733c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1734c2df9bbfSMatthew G. Knepley                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1735c2df9bbfSMatthew G. Knepley               } else if (vx == 0) {
17369566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1737c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1738c2df9bbfSMatthew G. Knepley                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
17393dfda0b1SToby Isaac               }
17403dfda0b1SToby Isaac             }
17413dfda0b1SToby Isaac             if (bdY != DM_BOUNDARY_PERIODIC) {
17423dfda0b1SToby Isaac               if (vy == numYVertices - 1) {
17439566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1744c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1745c2df9bbfSMatthew G. Knepley                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1746c2df9bbfSMatthew G. Knepley               } else if (vy == 0) {
17479566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1748c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1749c2df9bbfSMatthew G. Knepley                 if (ez == numZEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
17503dfda0b1SToby Isaac               }
17513dfda0b1SToby Isaac             }
17523dfda0b1SToby Isaac           }
17533dfda0b1SToby Isaac         }
17543dfda0b1SToby Isaac       }
17553dfda0b1SToby Isaac     }
17563dfda0b1SToby Isaac     /* Build Y edges*/
17573dfda0b1SToby Isaac     for (vz = 0; vz < numZVertices; vz++) {
17583dfda0b1SToby Isaac       for (vx = 0; vx < numXVertices; vx++) {
17593dfda0b1SToby Isaac         for (ey = 0; ey < numYEdges; ey++) {
17603dfda0b1SToby Isaac           const PetscInt nextv   = (dim == 2 && bdY == DM_BOUNDARY_TWIST && ey == numYEdges - 1) ? (numXVertices - vx - 1) : (vz * numYVertices + ((ey + 1) % numYVertices)) * numXVertices + vx;
17613dfda0b1SToby Isaac           const PetscInt edge    = firstYEdge + (vz * numXVertices + vx) * numYEdges + ey;
17623dfda0b1SToby Isaac           const PetscInt vertexF = firstVertex + (vz * numYVertices + ey) * numXVertices + vx;
17633dfda0b1SToby Isaac           const PetscInt vertexK = firstVertex + nextv;
17643dfda0b1SToby Isaac           PetscInt       cone[2];
17653dfda0b1SToby Isaac 
17669371c9d4SSatish Balay           cone[0] = vertexF;
17679371c9d4SSatish Balay           cone[1] = vertexK;
17689566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, edge, cone));
17693dfda0b1SToby Isaac           if (dim == 2) {
17703dfda0b1SToby Isaac             if ((bdX != DM_BOUNDARY_PERIODIC) && (bdX != DM_BOUNDARY_TWIST)) {
17713dfda0b1SToby Isaac               if (vx == numXVertices - 1) {
17729566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerRight));
17739566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
17749566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1775c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1776d8211ee3SMatthew G. Knepley               } else if (vx == 0) {
17779566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerLeft));
17789566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
17799566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1780c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
17813dfda0b1SToby Isaac               }
1782d8211ee3SMatthew G. Knepley             } else {
17834c67ea77SStefano Zampini               if (vx == 0 && cutLabel) {
17849566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
17859566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1786c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
17873dfda0b1SToby Isaac               }
1788d8211ee3SMatthew G. Knepley             }
1789d8211ee3SMatthew G. Knepley           } else {
17903dfda0b1SToby Isaac             if (bdX != DM_BOUNDARY_PERIODIC) {
17913dfda0b1SToby Isaac               if (vx == numXVertices - 1) {
17929566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerRight));
1793c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerRight));
1794c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerRight));
1795d8211ee3SMatthew G. Knepley               } else if (vx == 0) {
17969566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerLeft));
1797c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerLeft));
1798c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerLeft));
17993dfda0b1SToby Isaac               }
18003dfda0b1SToby Isaac             }
18013dfda0b1SToby Isaac             if (bdZ != DM_BOUNDARY_PERIODIC) {
18023dfda0b1SToby Isaac               if (vz == numZVertices - 1) {
18039566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1804c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1805c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1806d8211ee3SMatthew G. Knepley               } else if (vz == 0) {
18079566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1808c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1809c2df9bbfSMatthew G. Knepley                 if (ey == numYEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
18103dfda0b1SToby Isaac               }
18113dfda0b1SToby Isaac             }
18123dfda0b1SToby Isaac           }
18133dfda0b1SToby Isaac         }
18143dfda0b1SToby Isaac       }
18153dfda0b1SToby Isaac     }
18163dfda0b1SToby Isaac     /* Build X edges*/
18173dfda0b1SToby Isaac     for (vz = 0; vz < numZVertices; vz++) {
18183dfda0b1SToby Isaac       for (vy = 0; vy < numYVertices; vy++) {
18193dfda0b1SToby Isaac         for (ex = 0; ex < numXEdges; ex++) {
18203dfda0b1SToby Isaac           const PetscInt nextv   = (dim == 2 && bdX == DM_BOUNDARY_TWIST && ex == numXEdges - 1) ? (numYVertices - vy - 1) * numXVertices : (vz * numYVertices + vy) * numXVertices + (ex + 1) % numXVertices;
18213dfda0b1SToby Isaac           const PetscInt edge    = firstXEdge + (vz * numYVertices + vy) * numXEdges + ex;
18223dfda0b1SToby Isaac           const PetscInt vertexL = firstVertex + (vz * numYVertices + vy) * numXVertices + ex;
18233dfda0b1SToby Isaac           const PetscInt vertexR = firstVertex + nextv;
18243dfda0b1SToby Isaac           PetscInt       cone[2];
18253dfda0b1SToby Isaac 
18269371c9d4SSatish Balay           cone[0] = vertexL;
18279371c9d4SSatish Balay           cone[1] = vertexR;
18289566063dSJacob Faibussowitsch           PetscCall(DMPlexSetCone(dm, edge, cone));
18293dfda0b1SToby Isaac           if (dim == 2) {
18303dfda0b1SToby Isaac             if ((bdY != DM_BOUNDARY_PERIODIC) && (bdY != DM_BOUNDARY_TWIST)) {
18313dfda0b1SToby Isaac               if (vy == numYVertices - 1) {
18329566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerTop));
18339566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
18349566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1835c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1836d8211ee3SMatthew G. Knepley               } else if (vy == 0) {
18379566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "Face Sets", edge, faceMarkerBottom));
18389566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
18399566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1840c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
18413dfda0b1SToby Isaac               }
1842d8211ee3SMatthew G. Knepley             } else {
18434c67ea77SStefano Zampini               if (vy == 0 && cutLabel) {
18449566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(cutLabel, edge, 1));
18459566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(cutLabel, cone[0], 1));
1846c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMLabelSetValue(cutLabel, cone[1], 1));
18473dfda0b1SToby Isaac               }
1848d8211ee3SMatthew G. Knepley             }
1849d8211ee3SMatthew G. Knepley           } else {
18503dfda0b1SToby Isaac             if (bdY != DM_BOUNDARY_PERIODIC) {
18513dfda0b1SToby Isaac               if (vy == numYVertices - 1) {
18529566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBack));
1853c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBack));
1854c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBack));
1855c2df9bbfSMatthew G. Knepley               } else if (vy == 0) {
18569566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerFront));
1857c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerFront));
1858c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerFront));
18593dfda0b1SToby Isaac               }
18603dfda0b1SToby Isaac             }
18613dfda0b1SToby Isaac             if (bdZ != DM_BOUNDARY_PERIODIC) {
18623dfda0b1SToby Isaac               if (vz == numZVertices - 1) {
18639566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerTop));
1864c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerTop));
1865c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerTop));
1866c2df9bbfSMatthew G. Knepley               } else if (vz == 0) {
18679566063dSJacob Faibussowitsch                 PetscCall(DMSetLabelValue(dm, "marker", edge, markerBottom));
1868c2df9bbfSMatthew G. Knepley                 PetscCall(DMSetLabelValue(dm, "marker", cone[0], markerBottom));
1869c2df9bbfSMatthew G. Knepley                 if (ex == numXEdges - 1) PetscCall(DMSetLabelValue(dm, "marker", cone[1], markerBottom));
18703dfda0b1SToby Isaac               }
18713dfda0b1SToby Isaac             }
18723dfda0b1SToby Isaac           }
18733dfda0b1SToby Isaac         }
18743dfda0b1SToby Isaac       }
18753dfda0b1SToby Isaac     }
18769566063dSJacob Faibussowitsch     PetscCall(DMPlexSymmetrize(dm));
18779566063dSJacob Faibussowitsch     PetscCall(DMPlexStratify(dm));
18783dfda0b1SToby Isaac     /* Build coordinates */
18799566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
18809566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(coordSection, 1));
18819566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
18829566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVertices));
18833dfda0b1SToby Isaac     for (v = firstVertex; v < firstVertex + numVertices; ++v) {
18849566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(coordSection, v, dim));
18859566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
18863dfda0b1SToby Isaac     }
18879566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(coordSection));
18889566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
18899566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
18909566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
18919566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
18929566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(coordinates, dim));
18939566063dSJacob Faibussowitsch     PetscCall(VecSetType(coordinates, VECSTANDARD));
18949566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
18953dfda0b1SToby Isaac     for (vz = 0; vz < numZVertices; ++vz) {
18963dfda0b1SToby Isaac       for (vy = 0; vy < numYVertices; ++vy) {
18973dfda0b1SToby Isaac         for (vx = 0; vx < numXVertices; ++vx) {
18983dfda0b1SToby Isaac           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 0] = lower[0] + ((upper[0] - lower[0]) / numXEdges) * vx;
18993dfda0b1SToby Isaac           coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 1] = lower[1] + ((upper[1] - lower[1]) / numYEdges) * vy;
1900ad540459SPierre Jolivet           if (dim == 3) coords[((vz * numYVertices + vy) * numXVertices + vx) * dim + 2] = lower[2] + ((upper[2] - lower[2]) / numZEdges) * vz;
19013dfda0b1SToby Isaac         }
19023dfda0b1SToby Isaac       }
19033dfda0b1SToby Isaac     }
19049566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
19059566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
19069566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&coordinates));
19073dfda0b1SToby Isaac   }
19083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19093dfda0b1SToby Isaac }
19103dfda0b1SToby Isaac 
1911d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoxMesh_Tensor_Internal(DM dm, PetscInt dim, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
1912d71ae5a4SJacob Faibussowitsch {
19139318fe57SMatthew G. Knepley   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
19149318fe57SMatthew G. Knepley   PetscInt       fac[3] = {0, 0, 0}, d;
1915552f7358SJed Brown 
1916552f7358SJed Brown   PetscFunctionBegin;
19174f572ea9SToby Isaac   PetscAssertPointer(dm, 1);
19189318fe57SMatthew G. Knepley   PetscValidLogicalCollectiveInt(dm, dim, 2);
19199566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
19209371c9d4SSatish Balay   for (d = 0; d < dim; ++d) {
19219371c9d4SSatish Balay     fac[d] = faces[d];
19229371c9d4SSatish Balay     bdt[d] = periodicity[d];
19239371c9d4SSatish Balay   }
19249566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateCubeMesh_Internal(dm, lower, upper, fac, bdt[0], bdt[1], bdt[2]));
19259371c9d4SSatish Balay   if (periodicity[0] == DM_BOUNDARY_PERIODIC || periodicity[0] == DM_BOUNDARY_TWIST || periodicity[1] == DM_BOUNDARY_PERIODIC || periodicity[1] == DM_BOUNDARY_TWIST || (dim > 2 && (periodicity[2] == DM_BOUNDARY_PERIODIC || periodicity[2] == DM_BOUNDARY_TWIST))) {
19266858538eSMatthew G. Knepley     PetscReal L[3]       = {-1., -1., 0.};
19276858538eSMatthew G. Knepley     PetscReal maxCell[3] = {-1., -1., 0.};
1928552f7358SJed Brown 
19299318fe57SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
19306858538eSMatthew G. Knepley       if (periodicity[d] != DM_BOUNDARY_NONE) {
19319318fe57SMatthew G. Knepley         L[d]       = upper[d] - lower[d];
19329318fe57SMatthew G. Knepley         maxCell[d] = 1.1 * (L[d] / PetscMax(1, faces[d]));
1933768d5fceSMatthew G. Knepley       }
19346858538eSMatthew G. Knepley     }
19354fb89dddSMatthew G. Knepley     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
1936768d5fceSMatthew G. Knepley   }
19379566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
19383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19399318fe57SMatthew G. Knepley }
19409318fe57SMatthew G. Knepley 
19415dca41c3SJed Brown static PetscErrorCode DMPlexCreateBoxMesh_Internal(DM dm, DMPlexShape shape, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate)
1942d71ae5a4SJacob Faibussowitsch {
19439318fe57SMatthew G. Knepley   PetscFunctionBegin;
194446139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
19455dca41c3SJed Brown   if (shape == DM_SHAPE_ZBOX) PetscCall(DMPlexCreateBoxMesh_Tensor_SFC_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
19466725e60dSJed Brown   else if (dim == 1) PetscCall(DMPlexCreateLineMesh_Internal(dm, faces[0], lower[0], upper[0], periodicity[0]));
19479566063dSJacob Faibussowitsch   else if (simplex) PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(dm, dim, faces, lower, upper, periodicity, interpolate));
19489566063dSJacob Faibussowitsch   else PetscCall(DMPlexCreateBoxMesh_Tensor_Internal(dm, dim, faces, lower, upper, periodicity));
19499318fe57SMatthew G. Knepley   if (!interpolate && dim > 1 && !simplex) {
1950768d5fceSMatthew G. Knepley     DM udm;
1951768d5fceSMatthew G. Knepley 
19529566063dSJacob Faibussowitsch     PetscCall(DMPlexUninterpolate(dm, &udm));
19539566063dSJacob Faibussowitsch     PetscCall(DMPlexCopyCoordinates(dm, udm));
195469d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &udm));
1955768d5fceSMatthew G. Knepley   }
195646139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
19573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1958c8c68bd8SToby Isaac }
1959c8c68bd8SToby Isaac 
19605d83a8b1SBarry Smith /*@
1961768d5fceSMatthew G. Knepley   DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box) using simplices or tensor cells (hexahedra).
1962768d5fceSMatthew G. Knepley 
1963d083f849SBarry Smith   Collective
1964768d5fceSMatthew G. Knepley 
1965768d5fceSMatthew G. Knepley   Input Parameters:
1966a1cb98faSBarry Smith + comm               - The communicator for the `DM` object
1967768d5fceSMatthew G. Knepley . dim                - The spatial dimension
1968a1cb98faSBarry Smith . simplex            - `PETSC_TRUE` for simplices, `PETSC_FALSE` for tensor cells
196920f4b53cSBarry Smith . faces              - Number of faces per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
197020f4b53cSBarry Smith . lower              - The lower left corner, or `NULL` for (0, 0, 0)
197120f4b53cSBarry Smith . upper              - The upper right corner, or `NULL` for (1, 1, 1)
197220f4b53cSBarry Smith . periodicity        - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
197342108689Sksagiyam . interpolate        - Flag to create intermediate mesh pieces (edges, faces)
197442108689Sksagiyam . localizationHeight - Flag to localize edges and faces in addition to cells; only significant for periodic meshes
197542108689Sksagiyam - sparseLocalize     - Flag to localize coordinates only for cells near the periodic boundary; only significant for periodic meshes
1976768d5fceSMatthew G. Knepley 
1977768d5fceSMatthew G. Knepley   Output Parameter:
1978a1cb98faSBarry Smith . dm - The `DM` object
1979768d5fceSMatthew G. Knepley 
1980768d5fceSMatthew G. Knepley   Level: beginner
1981768d5fceSMatthew G. Knepley 
1982a1cb98faSBarry Smith   Note:
1983a1cb98faSBarry Smith   To customize this mesh using options, use
1984a1cb98faSBarry Smith .vb
1985a1cb98faSBarry Smith   DMCreate(comm, &dm);
1986a1cb98faSBarry Smith   DMSetType(dm, DMPLEX);
1987a1cb98faSBarry Smith   DMSetFromOptions(dm);
1988a1cb98faSBarry Smith .ve
1989a1cb98faSBarry Smith   and use the options in `DMSetFromOptions()`.
1990a1cb98faSBarry Smith 
1991a4e35b19SJacob Faibussowitsch   Here is the numbering returned for 2 faces in each direction for tensor cells\:
1992a1cb98faSBarry Smith .vb
1993a1cb98faSBarry Smith  10---17---11---18----12
1994a1cb98faSBarry Smith   |         |         |
1995a1cb98faSBarry Smith   |         |         |
1996a1cb98faSBarry Smith  20    2   22    3    24
1997a1cb98faSBarry Smith   |         |         |
1998a1cb98faSBarry Smith   |         |         |
1999a1cb98faSBarry Smith   7---15----8---16----9
2000a1cb98faSBarry Smith   |         |         |
2001a1cb98faSBarry Smith   |         |         |
2002a1cb98faSBarry Smith  19    0   21    1   23
2003a1cb98faSBarry Smith   |         |         |
2004a1cb98faSBarry Smith   |         |         |
2005a1cb98faSBarry Smith   4---13----5---14----6
2006a1cb98faSBarry Smith .ve
2007a1cb98faSBarry Smith   and for simplicial cells
2008a1cb98faSBarry Smith .vb
2009a1cb98faSBarry Smith  14----8---15----9----16
2010a1cb98faSBarry Smith   |\     5  |\      7 |
2011a1cb98faSBarry Smith   | \       | \       |
2012a1cb98faSBarry Smith  13   2    14    3    15
2013a1cb98faSBarry Smith   | 4   \   | 6   \   |
2014a1cb98faSBarry Smith   |       \ |       \ |
2015a1cb98faSBarry Smith  11----6---12----7----13
2016a1cb98faSBarry Smith   |\        |\        |
2017a1cb98faSBarry Smith   | \    1  | \     3 |
2018a1cb98faSBarry Smith  10   0    11    1    12
2019a1cb98faSBarry Smith   | 0   \   | 2   \   |
2020a1cb98faSBarry Smith   |       \ |       \ |
2021a1cb98faSBarry Smith   8----4----9----5----10
2022a1cb98faSBarry Smith .ve
2023a1cb98faSBarry Smith 
20241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
2025768d5fceSMatthew G. Knepley @*/
202642108689Sksagiyam PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool interpolate, PetscInt localizationHeight, PetscBool sparseLocalize, DM *dm)
2027d71ae5a4SJacob Faibussowitsch {
20289318fe57SMatthew G. Knepley   PetscInt       fac[3] = {1, 1, 1};
2029fdbf62faSLisandro Dalcin   PetscReal      low[3] = {0, 0, 0};
2030fdbf62faSLisandro Dalcin   PetscReal      upp[3] = {1, 1, 1};
2031fdbf62faSLisandro Dalcin   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
2032552f7358SJed Brown 
2033768d5fceSMatthew G. Knepley   PetscFunctionBegin;
20349566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
20359566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
20365dca41c3SJed Brown   PetscCall(DMPlexCreateBoxMesh_Internal(*dm, DM_SHAPE_BOX, dim, simplex, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt, interpolate));
203742108689Sksagiyam   if (periodicity) {
203842108689Sksagiyam     DM cdm;
203942108689Sksagiyam 
204042108689Sksagiyam     PetscCall(DMGetCoordinateDM(*dm, &cdm));
204142108689Sksagiyam     PetscCall(DMPlexSetMaxProjectionHeight(cdm, localizationHeight));
204242108689Sksagiyam     PetscCall(DMSetSparseLocalize(*dm, sparseLocalize));
204342108689Sksagiyam     PetscCall(DMLocalizeCoordinates(*dm));
204442108689Sksagiyam   }
20453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20469318fe57SMatthew G. Knepley }
2047fdbf62faSLisandro Dalcin 
2048d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateWedgeBoxMesh_Internal(DM dm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[])
2049d71ae5a4SJacob Faibussowitsch {
20509318fe57SMatthew G. Knepley   DM       bdm, vol;
20519318fe57SMatthew G. Knepley   PetscInt i;
20529318fe57SMatthew G. Knepley 
20539318fe57SMatthew G. Knepley   PetscFunctionBegin;
20541fcf445aSMatthew G. Knepley   // TODO Now we can support periodicity
205508401ef6SPierre Jolivet   for (i = 0; i < 3; ++i) PetscCheck(periodicity[i] == DM_BOUNDARY_NONE, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Periodicity not yet supported");
20569566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &bdm));
20579566063dSJacob Faibussowitsch   PetscCall(DMSetType(bdm, DMPLEX));
20589566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(bdm, 2));
205946139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, bdm, 0, 0, 0));
20609566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateBoxMesh_Simplex_Internal(bdm, 2, faces, lower, upper, periodicity, PETSC_TRUE));
2061658b9581SMatthew G. Knepley   PetscCall(DMPlexExtrude(bdm, faces[2], upper[2] - lower[2], PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, NULL, NULL, NULL, &vol));
206246139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, bdm, 0, 0, 0));
20639566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&bdm));
206469d8a87bSksagiyam   PetscCall(DMPlexReplace_Internal(dm, &vol));
20659318fe57SMatthew G. Knepley   if (lower[2] != 0.0) {
20669318fe57SMatthew G. Knepley     Vec          v;
20679318fe57SMatthew G. Knepley     PetscScalar *x;
20689318fe57SMatthew G. Knepley     PetscInt     cDim, n;
20699318fe57SMatthew G. Knepley 
20709566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &v));
20719566063dSJacob Faibussowitsch     PetscCall(VecGetBlockSize(v, &cDim));
20729566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(v, &n));
20739566063dSJacob Faibussowitsch     PetscCall(VecGetArray(v, &x));
20749318fe57SMatthew G. Knepley     x += cDim;
20759318fe57SMatthew G. Knepley     for (i = 0; i < n; i += cDim) x[i] += lower[2];
20769566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(v, &x));
20779566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinatesLocal(dm, v));
20789318fe57SMatthew G. Knepley   }
20793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2080552f7358SJed Brown }
2081552f7358SJed Brown 
208200dabe28SStefano Zampini /*@
208339f4f5dbSPierre Jolivet   DMPlexCreateWedgeBoxMesh - Creates a 3-D mesh tessellating the (x,y) plane and extruding in the third direction using wedge cells.
208400dabe28SStefano Zampini 
2085d083f849SBarry Smith   Collective
208600dabe28SStefano Zampini 
208700dabe28SStefano Zampini   Input Parameters:
2088a1cb98faSBarry Smith + comm        - The communicator for the `DM` object
208920f4b53cSBarry Smith . faces       - Number of faces per dimension, or `NULL` for (1, 1, 1)
209020f4b53cSBarry Smith . lower       - The lower left corner, or `NULL` for (0, 0, 0)
209120f4b53cSBarry Smith . upper       - The upper right corner, or `NULL` for (1, 1, 1)
209220f4b53cSBarry Smith . periodicity - The boundary type for the X,Y,Z direction, or `NULL` for `DM_BOUNDARY_NONE`
2093a1cb98faSBarry Smith . orderHeight - If `PETSC_TRUE`, orders the extruded cells in the height first. Otherwise, orders the cell on the layers first
209400dabe28SStefano Zampini - interpolate - Flag to create intermediate mesh pieces (edges, faces)
209500dabe28SStefano Zampini 
209600dabe28SStefano Zampini   Output Parameter:
2097a1cb98faSBarry Smith . dm - The `DM` object
209800dabe28SStefano Zampini 
209900dabe28SStefano Zampini   Level: beginner
210000dabe28SStefano Zampini 
21011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateWedgeCylinderMesh()`, `DMExtrude()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
210200dabe28SStefano Zampini @*/
2103d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateWedgeBoxMesh(MPI_Comm comm, const PetscInt faces[], const PetscReal lower[], const PetscReal upper[], const DMBoundaryType periodicity[], PetscBool orderHeight, PetscBool interpolate, DM *dm)
2104d71ae5a4SJacob Faibussowitsch {
21059318fe57SMatthew G. Knepley   PetscInt       fac[3] = {1, 1, 1};
210600dabe28SStefano Zampini   PetscReal      low[3] = {0, 0, 0};
210700dabe28SStefano Zampini   PetscReal      upp[3] = {1, 1, 1};
210800dabe28SStefano Zampini   DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
210900dabe28SStefano Zampini 
211000dabe28SStefano Zampini   PetscFunctionBegin;
21119566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
21129566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
21139566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateWedgeBoxMesh_Internal(*dm, faces ? faces : fac, lower ? lower : low, upper ? upper : upp, periodicity ? periodicity : bdt));
2114d410b0cfSMatthew G. Knepley   if (!interpolate) {
2115d410b0cfSMatthew G. Knepley     DM udm;
211600dabe28SStefano Zampini 
21179566063dSJacob Faibussowitsch     PetscCall(DMPlexUninterpolate(*dm, &udm));
211869d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(*dm, &udm));
211900dabe28SStefano Zampini   }
21207ff04441SMatthew G. Knepley   if (periodicity) PetscCall(DMLocalizeCoordinates(*dm));
21213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
212200dabe28SStefano Zampini }
212300dabe28SStefano Zampini 
2124cfb853baSMatthew G. Knepley /*
2125cfb853baSMatthew G. Knepley   DMPlexTensorPointLexicographic_Private - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max' for that dimension.
2126cfb853baSMatthew G. Knepley 
2127cfb853baSMatthew G. Knepley   Input Parameters:
2128cfb853baSMatthew G. Knepley + len - The length of the tuple
2129cfb853baSMatthew G. Knepley . max - The maximum for each dimension, so values are in [0, max)
2130cfb853baSMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
2131cfb853baSMatthew G. Knepley 
2132cfb853baSMatthew G. Knepley   Output Parameter:
213320f4b53cSBarry Smith . tup - A tuple of `len` integers whose entries are at most `max`
2134cfb853baSMatthew G. Knepley 
2135cfb853baSMatthew G. Knepley   Level: developer
2136cfb853baSMatthew G. Knepley 
213720f4b53cSBarry Smith   Note:
213820f4b53cSBarry Smith   Ordering is lexicographic with lowest index as least significant in ordering.
213920f4b53cSBarry Smith   e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.
214020f4b53cSBarry Smith 
2141cfb853baSMatthew G. Knepley .seealso: PetscDualSpaceTensorPointLexicographic_Internal(), PetscDualSpaceLatticePointLexicographic_Internal()
2142cfb853baSMatthew G. Knepley */
2143cfb853baSMatthew G. Knepley static PetscErrorCode DMPlexTensorPointLexicographic_Private(PetscInt len, const PetscInt max[], PetscInt tup[])
2144cfb853baSMatthew G. Knepley {
2145cfb853baSMatthew G. Knepley   PetscInt i;
2146cfb853baSMatthew G. Knepley 
2147cfb853baSMatthew G. Knepley   PetscFunctionBegin;
2148cfb853baSMatthew G. Knepley   for (i = 0; i < len; ++i) {
2149cfb853baSMatthew G. Knepley     if (tup[i] < max[i] - 1) {
2150cfb853baSMatthew G. Knepley       break;
2151cfb853baSMatthew G. Knepley     } else {
2152cfb853baSMatthew G. Knepley       tup[i] = 0;
2153cfb853baSMatthew G. Knepley     }
2154cfb853baSMatthew G. Knepley   }
2155cfb853baSMatthew G. Knepley   if (i == len) tup[i - 1] = max[i - 1];
2156cfb853baSMatthew G. Knepley   else ++tup[i];
21573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2158cfb853baSMatthew G. Knepley }
2159cfb853baSMatthew G. Knepley 
2160cfb853baSMatthew G. Knepley static PetscInt TupleToIndex_Private(PetscInt len, const PetscInt max[], const PetscInt tup[])
2161cfb853baSMatthew G. Knepley {
21628d2ec52aSSatish Balay   PetscInt idx = tup[len - 1];
2163cfb853baSMatthew G. Knepley 
21648d2ec52aSSatish Balay   for (PetscInt i = len - 2; i >= 0; --i) {
2165cfb853baSMatthew G. Knepley     idx *= max[i];
2166cfb853baSMatthew G. Knepley     idx += tup[i];
2167cfb853baSMatthew G. Knepley   }
2168cfb853baSMatthew G. Knepley   return idx;
2169cfb853baSMatthew G. Knepley }
2170cfb853baSMatthew G. Knepley 
21718d2ec52aSSatish Balay static void IndexToTuple_Private(PetscInt len, const PetscInt max[], PetscInt idx, PetscInt tup[])
2172cfb853baSMatthew G. Knepley {
21738d2ec52aSSatish Balay   for (PetscInt i = 0; i < len; ++i) {
21748d2ec52aSSatish Balay     tup[i] = idx % max[i];
21758d2ec52aSSatish Balay     idx    = (idx - tup[i]) / max[i];
21768d2ec52aSSatish Balay   }
21778d2ec52aSSatish Balay }
21788d2ec52aSSatish Balay 
21798d2ec52aSSatish Balay static void TupleToRanks_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt tup[], PetscInt ranks[])
21808d2ec52aSSatish Balay {
21818d2ec52aSSatish Balay   for (PetscInt i = 0; i < len; ++i) {
21828d2ec52aSSatish Balay     const PetscInt div = max[i] / procs[i];
21838d2ec52aSSatish Balay     const PetscInt rem = max[i] % procs[i];
21848d2ec52aSSatish Balay     const PetscInt idx = (tup[i] < 0 ? max[i] + tup[i] : tup[i]) % max[i];
21858d2ec52aSSatish Balay 
21868d2ec52aSSatish Balay     if (idx < rem * (div + 1)) ranks[i] = idx / (div + 1);
21878d2ec52aSSatish Balay     else ranks[i] = rem + (idx - rem * (div + 1)) / div;
21888d2ec52aSSatish Balay   }
21898d2ec52aSSatish Balay }
21908d2ec52aSSatish Balay 
21918d2ec52aSSatish Balay static void RanksToSizes_Private(PetscInt len, const PetscInt max[], const PetscInt procs[], const PetscInt ranks[], PetscInt sizes[])
21928d2ec52aSSatish Balay {
21938d2ec52aSSatish Balay   for (PetscInt i = 0; i < len; ++i) {
21948d2ec52aSSatish Balay     const PetscInt div = max[i] / procs[i];
21958d2ec52aSSatish Balay     const PetscInt rem = max[i] % procs[i];
21968d2ec52aSSatish Balay 
21978d2ec52aSSatish Balay     sizes[i] = ranks[i] < rem ? div + 1 : div;
21988d2ec52aSSatish Balay   }
21998d2ec52aSSatish Balay }
22008d2ec52aSSatish Balay 
22018d2ec52aSSatish Balay /*
22028d2ec52aSSatish Balay   In serial, the mesh is completely periodic. In parallel, we will include a layer of ghost vertices around the patch, so our edges will not wrap around in parallel. This will instead be handled by the SF.
22038d2ec52aSSatish Balay 
22048d2ec52aSSatish Balay   The cone for all edges will always be complete. Even in the presence of boundaries, we will keep all support sizes constant. When an edge would not exist in the support, we will create one to wrap back periodically. This allows for uniform stencils, and that edge will not be used for computation.
22058d2ec52aSSatish Balay 
22068d2ec52aSSatish Balay   All point which do not attain the vertex lower or upper bound in any dimension are owned, the rest are leaves owned by another process and present in the SF.
2207dfe9cfe5SMatthew Knepley 
2208dfe9cfe5SMatthew Knepley   Parallel Layout:
2209dfe9cfe5SMatthew Knepley 
2210dfe9cfe5SMatthew Knepley   We create a cubic process grid of dimension P^{1/d} on each side. The IndexToTuple_Private() function maps the global rank to the local rank in each dimension. We divide edges using the PETSc distribution rule in each dimension, and then add overlap. TupleToRanks_Private() returns the local rank in ech dimension for a tuple. RanksToSizes_Private() gives the size in each dimension for the domain with those local ranks.
22118d2ec52aSSatish Balay */
22128d2ec52aSSatish Balay static PetscErrorCode DMPlexCreateHypercubicMesh_Internal(DM dm, PetscInt dim, const PetscReal lower[], const PetscReal upper[], const PetscInt edges[], PetscInt overlap, const DMBoundaryType bd[])
22138d2ec52aSSatish Balay {
22148d2ec52aSSatish Balay   const PetscInt debug = ((DM_Plex *)dm->data)->printAdj;
22158d2ec52aSSatish Balay   PetscSF        sf;
2216cfb853baSMatthew G. Knepley   Vec            coordinates;
2217cfb853baSMatthew G. Knepley   PetscSection   coordSection;
2218cfb853baSMatthew G. Knepley   DMLabel        cutLabel    = NULL;
2219cfb853baSMatthew G. Knepley   PetscBool      cutMarker   = PETSC_FALSE;
2220cfb853baSMatthew G. Knepley   PetscBool      periodic    = PETSC_FALSE;
22218d2ec52aSSatish Balay   PetscInt       numCells    = 1;
22228d2ec52aSSatish Balay   PetscInt       numVertices = 1;
22238d2ec52aSSatish Balay   PetscSFNode   *remotes;
2224cfb853baSMatthew G. Knepley   PetscScalar   *coords;
22258d2ec52aSSatish Balay   PetscInt      *procs;     // The number of processes along each dimension
22268d2ec52aSSatish Balay   PetscInt      *lrank;     // Rank in each dimension, lrank[d] \in [0, procs[d])
22278d2ec52aSSatish Balay   PetscInt      *ledges;    // The number of edges along each dimension for this process
22288d2ec52aSSatish Balay   PetscInt      *vstart;    // The first vertex along each dimension on this processes
22298d2ec52aSSatish Balay   PetscInt      *vertices;  // The number of vertices along each dimension on this process
22308d2ec52aSSatish Balay   PetscInt      *rvert;     // The global (not local) vertex number along each dimension
22318d2ec52aSSatish Balay   PetscInt      *rrank;     // The rank along each dimension for the process owning rvert[]
22328d2ec52aSSatish Balay   PetscInt      *rvertices; // The number of vertices along each dimension for the process rrank[]
22338d2ec52aSSatish Balay   PetscInt      *vert, *vtmp, *supp, cone[2], *leaves;
22348d2ec52aSSatish Balay   PetscInt       cell = 0, coordSize, Nl = 0, Nl2 = 0;
22358d2ec52aSSatish Balay   PetscMPIInt    rank, size;
22368d2ec52aSSatish Balay   MPI_Comm       comm;
2237cfb853baSMatthew G. Knepley 
2238cfb853baSMatthew G. Knepley   PetscFunctionBegin;
22398d2ec52aSSatish Balay   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
22408d2ec52aSSatish Balay   PetscCallMPI(MPI_Comm_rank(comm, &rank));
22418d2ec52aSSatish Balay   PetscCallMPI(MPI_Comm_size(comm, &size));
2242cfb853baSMatthew G. Knepley   PetscCall(DMSetDimension(dm, dim));
22438d2ec52aSSatish Balay   PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
22448d2ec52aSSatish Balay   PetscCall(PetscCalloc4(dim, &procs, dim, &lrank, dim, &rrank, 2 * dim, &supp));
22458d2ec52aSSatish Balay   PetscCall(PetscCalloc7(dim, &ledges, dim, &vertices, dim, &rvertices, dim, &vert, dim, &rvert, dim, &vstart, dim, &vtmp));
2246cfb853baSMatthew G. Knepley   PetscCall(DMCreateLabel(dm, "marker"));
2247cfb853baSMatthew G. Knepley   PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_periodic_cut", &cutMarker, NULL));
22488d2ec52aSSatish Balay   for (PetscInt d = 0; d < dim; ++d) periodic = (periodic || bd[d] == DM_BOUNDARY_PERIODIC) ? PETSC_TRUE : PETSC_FALSE;
2249cfb853baSMatthew G. Knepley   if (periodic && cutMarker) {
2250cfb853baSMatthew G. Knepley     PetscCall(DMCreateLabel(dm, "periodic_cut"));
2251cfb853baSMatthew G. Knepley     PetscCall(DMGetLabel(dm, "periodic_cut", &cutLabel));
2252cfb853baSMatthew G. Knepley   }
22538d2ec52aSSatish Balay   for (PetscInt d = 0; d < dim; ++d) PetscCheck(bd[d] == DM_BOUNDARY_PERIODIC, comm, PETSC_ERR_SUP, "Hypercubic mesh must be periodic now");
22548d2ec52aSSatish Balay   overlap = overlap == PETSC_DETERMINE ? 1 : overlap;
22558d2ec52aSSatish Balay   PetscCheck(overlap >= 1, comm, PETSC_ERR_SUP, "Overlap %" PetscInt_FMT " must be greater than 0", overlap);
22568d2ec52aSSatish Balay   if (size > 1) {
22578d2ec52aSSatish Balay     PetscInt Npr = 1;
22588d2ec52aSSatish Balay 
22598d2ec52aSSatish Balay     // Make process grid
22608d2ec52aSSatish Balay     if (debug) PetscCall(PetscPrintf(comm, "Process grid:"));
22618d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
22628d2ec52aSSatish Balay       procs[d] = PetscRintReal(PetscPowReal(size, 1. / dim));
22638d2ec52aSSatish Balay       Npr *= procs[d];
22648d2ec52aSSatish Balay       if (debug) PetscCall(PetscPrintf(comm, " %" PetscInt_FMT, procs[d]));
22658d2ec52aSSatish Balay     }
22668d2ec52aSSatish Balay     if (debug) PetscCall(PetscPrintf(comm, "\n"));
22678d2ec52aSSatish Balay     PetscCheck(Npr == size, comm, PETSC_ERR_PLIB, "Process grid size %" PetscInt_FMT " != %d comm size", Npr, size);
22688d2ec52aSSatish Balay     IndexToTuple_Private(dim, procs, rank, lrank);
22698d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
22708d2ec52aSSatish Balay       ledges[d] = edges[d] / procs[d] + (edges[d] % procs[d] > lrank[d] ? 1 : 0);
22718d2ec52aSSatish Balay       vstart[d] = 0;
22728d2ec52aSSatish Balay       for (PetscInt r = 0; r < lrank[d]; ++r) vstart[d] += edges[d] / procs[d] + (edges[d] % procs[d] > r ? 1 : 0);
22738d2ec52aSSatish Balay       vstart[d] -= overlap; // For halo
22748d2ec52aSSatish Balay     }
22758d2ec52aSSatish Balay   } else {
22768d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
22778d2ec52aSSatish Balay       procs[d]  = 1;
22788d2ec52aSSatish Balay       ledges[d] = edges[d];
22798d2ec52aSSatish Balay     }
22808d2ec52aSSatish Balay   }
22818d2ec52aSSatish Balay   // Calculate local patch size
22828d2ec52aSSatish Balay   for (PetscInt d = 0; d < dim; ++d) {
22838d2ec52aSSatish Balay     vertices[d] = ledges[d] + (procs[d] > 1 ? 2 * overlap : 0);
2284cfb853baSMatthew G. Knepley     numVertices *= vertices[d];
2285cfb853baSMatthew G. Knepley   }
2286cfb853baSMatthew G. Knepley   numCells = numVertices * dim;
2287cfb853baSMatthew G. Knepley   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
22888d2ec52aSSatish Balay   for (PetscInt c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, 2));
22898d2ec52aSSatish Balay   for (PetscInt v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetSupportSize(dm, v, 2 * dim));
2290cfb853baSMatthew G. Knepley   PetscCall(DMSetUp(dm)); /* Allocate space for cones and supports */
2291cfb853baSMatthew G. Knepley   /* Build cell cones and vertex supports */
2292cfb853baSMatthew G. Knepley   PetscCall(DMCreateLabel(dm, "celltype"));
22938d2ec52aSSatish Balay   if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Topology for rank %d:\n", rank));
2294cfb853baSMatthew G. Knepley   while (vert[dim - 1] < vertices[dim - 1]) {
2295cfb853baSMatthew G. Knepley     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert) + numCells;
2296cfb853baSMatthew G. Knepley     PetscInt       s      = 0;
22978d2ec52aSSatish Balay     PetscBool      leaf   = PETSC_FALSE;
2298cfb853baSMatthew G. Knepley 
22998d2ec52aSSatish Balay     if (debug) {
23008d2ec52aSSatish Balay       PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex));
23018d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d]));
23028d2ec52aSSatish Balay       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
23038d2ec52aSSatish Balay     }
2304cfb853baSMatthew G. Knepley     PetscCall(DMPlexSetCellType(dm, vertex, DM_POLYTOPE_POINT));
23058d2ec52aSSatish Balay     // Define edge cones
23068d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
23078d2ec52aSSatish Balay       for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e];
2308cfb853baSMatthew G. Knepley       vtmp[d] = (vert[d] + 1) % vertices[d];
2309cfb853baSMatthew G. Knepley       cone[0] = vertex;
2310cfb853baSMatthew G. Knepley       cone[1] = TupleToIndex_Private(dim, vertices, vtmp) + numCells;
23118d2ec52aSSatish Balay       if (debug) {
23128d2ec52aSSatish Balay         PetscCall(PetscSynchronizedPrintf(comm, "  Vertex %" PetscInt_FMT ":", cone[1]));
23138d2ec52aSSatish Balay         for (PetscInt e = 0; e < dim; ++e) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vtmp[e]));
23148d2ec52aSSatish Balay         PetscCall(PetscSynchronizedPrintf(comm, "\n"));
23158d2ec52aSSatish Balay       }
2316cfb853baSMatthew G. Knepley       PetscCall(DMPlexSetCone(dm, cell, cone));
2317cfb853baSMatthew G. Knepley       PetscCall(DMPlexSetCellType(dm, cell, DM_POLYTOPE_SEGMENT));
23188d2ec52aSSatish Balay       if (debug) PetscCall(PetscSynchronizedPrintf(comm, "  Edge %" PetscInt_FMT " (%" PetscInt_FMT " %" PetscInt_FMT ")\n", cell, cone[0], cone[1]));
2319cfb853baSMatthew G. Knepley       ++cell;
23208d2ec52aSSatish Balay       // Shared vertices are any in the first or last overlap layers
23218d2ec52aSSatish Balay       if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE;
2322cfb853baSMatthew G. Knepley     }
23238d2ec52aSSatish Balay     if (size > 1 && leaf) ++Nl;
23248d2ec52aSSatish Balay     // Define vertex supports
23258d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
23268d2ec52aSSatish Balay       for (PetscInt e = 0; e < dim; ++e) vtmp[e] = vert[e];
2327cfb853baSMatthew G. Knepley       vtmp[d]   = (vert[d] + vertices[d] - 1) % vertices[d];
2328cfb853baSMatthew G. Knepley       supp[s++] = TupleToIndex_Private(dim, vertices, vtmp) * dim + d;
2329cfb853baSMatthew G. Knepley       supp[s++] = (vertex - numCells) * dim + d;
2330cfb853baSMatthew G. Knepley       PetscCall(DMPlexSetSupport(dm, vertex, supp));
2331cfb853baSMatthew G. Knepley     }
2332cfb853baSMatthew G. Knepley     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
2333cfb853baSMatthew G. Knepley   }
23348d2ec52aSSatish Balay   if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL));
2335cfb853baSMatthew G. Knepley   PetscCall(DMPlexStratify(dm));
23368d2ec52aSSatish Balay   // Allocate for SF
23378d2ec52aSSatish Balay   PetscCall(PetscMalloc1(Nl, &leaves));
23388d2ec52aSSatish Balay   PetscCall(PetscMalloc1(Nl, &remotes));
23398d2ec52aSSatish Balay   // Build coordinates
2340cfb853baSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(dm, &coordSection));
2341cfb853baSMatthew G. Knepley   PetscCall(PetscSectionSetNumFields(coordSection, 1));
2342cfb853baSMatthew G. Knepley   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
2343cfb853baSMatthew G. Knepley   PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
23448d2ec52aSSatish Balay   for (PetscInt v = numCells; v < numCells + numVertices; ++v) {
2345cfb853baSMatthew G. Knepley     PetscCall(PetscSectionSetDof(coordSection, v, dim));
2346cfb853baSMatthew G. Knepley     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
2347cfb853baSMatthew G. Knepley   }
2348cfb853baSMatthew G. Knepley   PetscCall(PetscSectionSetUp(coordSection));
2349cfb853baSMatthew G. Knepley   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
23508d2ec52aSSatish Balay   PetscCall(VecCreate(comm, &coordinates));
2351cfb853baSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2352cfb853baSMatthew G. Knepley   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
2353cfb853baSMatthew G. Knepley   PetscCall(VecSetBlockSize(coordinates, dim));
2354cfb853baSMatthew G. Knepley   PetscCall(VecSetType(coordinates, VECSTANDARD));
2355cfb853baSMatthew G. Knepley   PetscCall(VecGetArray(coordinates, &coords));
23568d2ec52aSSatish Balay   if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Geometry for rank %d:\n", rank));
23578d2ec52aSSatish Balay   for (PetscInt d = 0; d < dim; ++d) vert[d] = 0;
2358cfb853baSMatthew G. Knepley   while (vert[dim - 1] < vertices[dim - 1]) {
2359cfb853baSMatthew G. Knepley     const PetscInt vertex = TupleToIndex_Private(dim, vertices, vert);
23608d2ec52aSSatish Balay     PetscBool      leaf   = PETSC_FALSE;
2361cfb853baSMatthew G. Knepley 
23628d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
23638d2ec52aSSatish Balay       coords[vertex * dim + d] = lower[d] + ((upper[d] - lower[d]) / edges[d]) * (vert[d] + vstart[d]);
23648d2ec52aSSatish Balay       if (vert[d] < overlap || vert[d] >= vertices[d] - overlap) leaf = PETSC_TRUE;
23658d2ec52aSSatish Balay     }
23668d2ec52aSSatish Balay     if (size > 1 && leaf) {
23678d2ec52aSSatish Balay       PetscInt rnumCells = 1;
23688d2ec52aSSatish Balay 
23698d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) rvert[d] = vert[d] + vstart[d];
23708d2ec52aSSatish Balay       TupleToRanks_Private(dim, edges, procs, rvert, rrank);
23718d2ec52aSSatish Balay       leaves[Nl2]       = vertex + numCells;
23728d2ec52aSSatish Balay       remotes[Nl2].rank = TupleToIndex_Private(dim, procs, rrank);
23738d2ec52aSSatish Balay       RanksToSizes_Private(dim, edges, procs, rrank, rvertices);
23748d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) {
23758d2ec52aSSatish Balay         rvertices[d] += 2 * overlap; // Add halo
23768d2ec52aSSatish Balay         rnumCells *= rvertices[d];
23778d2ec52aSSatish Balay       }
23788d2ec52aSSatish Balay       rnumCells *= dim;
23798d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) {
23808d2ec52aSSatish Balay         const PetscInt diff = rrank[d] - lrank[d];
23818d2ec52aSSatish Balay 
23828d2ec52aSSatish Balay         if (!diff) rvert[d] = vert[d];                                     // Vertex is local
23838d2ec52aSSatish Balay         else if (rvert[d] < 0) rvert[d] = rvertices[d] - 1 + rvert[d];     // Wrap around at the bottom
23848d2ec52aSSatish Balay         else if (rvert[d] >= edges[d]) rvert[d] = rvert[d] - edges[d] + 1; // Wrap around at the top
23858d2ec52aSSatish Balay         else if (diff == -1) rvert[d] = rvertices[d] - 1 + (vert[d] - overlap);
23868d2ec52aSSatish Balay         else if (diff == 1) rvert[d] = (vertices[d] - vert[d] - 1) + overlap;
23878d2ec52aSSatish Balay         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Process distance %" PetscInt_FMT " in direction %" PetscInt_FMT " should not be possible", diff, d);
23888d2ec52aSSatish Balay       }
23898d2ec52aSSatish Balay       remotes[Nl2].index = TupleToIndex_Private(dim, rvertices, rvert) + rnumCells;
23908d2ec52aSSatish Balay       if (debug) PetscCall(PetscSynchronizedPrintf(comm, "Shared Vertex %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", leaves[Nl2], remotes[Nl2].rank, remotes[Nl2].index));
23918d2ec52aSSatish Balay       ++Nl2;
23928d2ec52aSSatish Balay     }
23938d2ec52aSSatish Balay     if (debug) {
23948d2ec52aSSatish Balay       PetscCall(PetscSynchronizedPrintf(comm, "Vertex %" PetscInt_FMT ":", vertex));
23958d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %" PetscInt_FMT, vert[d] + vstart[d]));
23968d2ec52aSSatish Balay       for (PetscInt d = 0; d < dim; ++d) PetscCall(PetscSynchronizedPrintf(comm, " %g", (double)PetscRealPart(coords[vertex * dim + d])));
23978d2ec52aSSatish Balay       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
23988d2ec52aSSatish Balay     }
2399cfb853baSMatthew G. Knepley     PetscCall(DMPlexTensorPointLexicographic_Private(dim, vertices, vert));
2400cfb853baSMatthew G. Knepley   }
24018d2ec52aSSatish Balay   if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL));
2402cfb853baSMatthew G. Knepley   PetscCall(VecRestoreArray(coordinates, &coords));
2403cfb853baSMatthew G. Knepley   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
2404cfb853baSMatthew G. Knepley   PetscCall(VecDestroy(&coordinates));
24058d2ec52aSSatish Balay   // Build SF
24068d2ec52aSSatish Balay   PetscCheck(Nl == Nl2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Initial number of leaves %" PetscInt_FMT " != %" PetscInt_FMT " final number", Nl, Nl2);
24078d2ec52aSSatish Balay   PetscCall(DMGetPointSF(dm, &sf));
24088d2ec52aSSatish Balay   PetscCall(PetscSFSetGraph(sf, numCells + numVertices, Nl, leaves, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
24098d2ec52aSSatish Balay   if (debug) PetscCall(PetscSFView(sf, PETSC_VIEWER_STDOUT_WORLD));
2410cfb853baSMatthew G. Knepley   //PetscCall(DMSetPeriodicity(dm, NULL, lower, upper));
2411cfb853baSMatthew G. Knepley   // Attach the extent
2412cfb853baSMatthew G. Knepley   {
2413cfb853baSMatthew G. Knepley     PetscContainer c;
24148d2ec52aSSatish Balay     PetscInt      *extent, *lextent;
2415cfb853baSMatthew G. Knepley 
2416cfb853baSMatthew G. Knepley     PetscCall(PetscMalloc1(dim, &extent));
24178d2ec52aSSatish Balay     PetscCall(PetscMalloc1(dim, &lextent));
24188d2ec52aSSatish Balay     for (PetscInt d = 0; d < dim; ++d) {
24198d2ec52aSSatish Balay       extent[d]  = edges[d];
24208d2ec52aSSatish Balay       lextent[d] = ledges[d];
24218d2ec52aSSatish Balay     }
2422cfb853baSMatthew G. Knepley     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
242349abdd8aSBarry Smith     PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault));
2424cfb853baSMatthew G. Knepley     PetscCall(PetscContainerSetPointer(c, extent));
2425cfb853baSMatthew G. Knepley     PetscCall(PetscObjectCompose((PetscObject)dm, "_extent", (PetscObject)c));
2426cfb853baSMatthew G. Knepley     PetscCall(PetscContainerDestroy(&c));
24278d2ec52aSSatish Balay     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c));
24288d2ec52aSSatish Balay     PetscCall(PetscContainerSetCtxDestroy(c, PetscCtxDestroyDefault));
24298d2ec52aSSatish Balay     PetscCall(PetscContainerSetPointer(c, lextent));
24308d2ec52aSSatish Balay     PetscCall(PetscObjectCompose((PetscObject)dm, "_lextent", (PetscObject)c));
24318d2ec52aSSatish Balay     PetscCall(PetscContainerDestroy(&c));
2432cfb853baSMatthew G. Knepley   }
24338d2ec52aSSatish Balay   PetscCall(PetscFree4(procs, lrank, rrank, supp));
24348d2ec52aSSatish Balay   PetscCall(PetscFree7(ledges, vertices, rvertices, vert, rvert, vstart, vtmp));
24353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2436cfb853baSMatthew G. Knepley }
2437cfb853baSMatthew G. Knepley 
2438cfb853baSMatthew G. Knepley /*@C
2439aaa8cc7dSPierre Jolivet   DMPlexCreateHypercubicMesh - Creates a periodic mesh on the tensor product of unit intervals using only vertices and edges.
2440cfb853baSMatthew G. Knepley 
2441cfb853baSMatthew G. Knepley   Collective
2442cfb853baSMatthew G. Knepley 
2443cfb853baSMatthew G. Knepley   Input Parameters:
24448d2ec52aSSatish Balay + comm    - The communicator for the `DM` object
2445cfb853baSMatthew G. Knepley . dim     - The spatial dimension
244620f4b53cSBarry Smith . edges   - Number of edges per dimension, or `NULL` for (1,) in 1D and (2, 2) in 2D and (1, 1, 1) in 3D
244720f4b53cSBarry Smith . lower   - The lower left corner, or `NULL` for (0, 0, 0)
24488d2ec52aSSatish Balay . upper   - The upper right corner, or `NULL` for (1, 1, 1)
24498d2ec52aSSatish Balay - overlap - The number of vertices in each direction to include in the overlap (default is 1)
2450cfb853baSMatthew G. Knepley 
2451cfb853baSMatthew G. Knepley   Output Parameter:
2452cfb853baSMatthew G. Knepley . dm - The DM object
2453cfb853baSMatthew G. Knepley 
245420f4b53cSBarry Smith   Level: beginner
245520f4b53cSBarry Smith 
245620f4b53cSBarry Smith   Note:
245720f4b53cSBarry Smith   If you want to customize this mesh using options, you just need to
245820f4b53cSBarry Smith .vb
245920f4b53cSBarry Smith   DMCreate(comm, &dm);
246020f4b53cSBarry Smith   DMSetType(dm, DMPLEX);
246120f4b53cSBarry Smith   DMSetFromOptions(dm);
246220f4b53cSBarry Smith .ve
246320f4b53cSBarry Smith   and use the options on the `DMSetFromOptions()` page.
2464cfb853baSMatthew G. Knepley 
2465cfb853baSMatthew G. Knepley   The vertices are numbered is lexicographic order, and the dim edges exiting a vertex in the positive orthant are number consecutively,
246620f4b53cSBarry Smith .vb
246720f4b53cSBarry Smith  18--0-19--2-20--4-18
246820f4b53cSBarry Smith   |     |     |     |
246920f4b53cSBarry Smith  13    15    17    13
247020f4b53cSBarry Smith   |     |     |     |
247120f4b53cSBarry Smith  24-12-25-14-26-16-24
247220f4b53cSBarry Smith   |     |     |     |
247320f4b53cSBarry Smith   7     9    11     7
247420f4b53cSBarry Smith   |     |     |     |
247520f4b53cSBarry Smith  21--6-22--8-23-10-21
247620f4b53cSBarry Smith   |     |     |     |
247720f4b53cSBarry Smith   1     3     5     1
247820f4b53cSBarry Smith   |     |     |     |
247920f4b53cSBarry Smith  18--0-19--2-20--4-18
248020f4b53cSBarry Smith .ve
2481cfb853baSMatthew G. Knepley 
248276fbde31SPierre Jolivet .seealso: `DMSetFromOptions()`, `DMPlexCreateFromFile()`, `DMPlexCreateHexCylinderMesh()`, `DMSetType()`, `DMCreate()`
2483cfb853baSMatthew G. Knepley @*/
24848d2ec52aSSatish Balay PetscErrorCode DMPlexCreateHypercubicMesh(MPI_Comm comm, PetscInt dim, const PetscInt edges[], const PetscReal lower[], const PetscReal upper[], PetscInt overlap, DM *dm)
2485cfb853baSMatthew G. Knepley {
2486cfb853baSMatthew G. Knepley   PetscInt       *edg;
2487cfb853baSMatthew G. Knepley   PetscReal      *low, *upp;
2488cfb853baSMatthew G. Knepley   DMBoundaryType *bdt;
2489cfb853baSMatthew G. Knepley   PetscInt        d;
2490cfb853baSMatthew G. Knepley 
2491cfb853baSMatthew G. Knepley   PetscFunctionBegin;
2492cfb853baSMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
2493cfb853baSMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
2494cfb853baSMatthew G. Knepley   PetscCall(PetscMalloc4(dim, &edg, dim, &low, dim, &upp, dim, &bdt));
2495cfb853baSMatthew G. Knepley   for (d = 0; d < dim; ++d) {
2496cfb853baSMatthew G. Knepley     edg[d] = edges ? edges[d] : 1;
2497cfb853baSMatthew G. Knepley     low[d] = lower ? lower[d] : 0.;
2498cfb853baSMatthew G. Knepley     upp[d] = upper ? upper[d] : 1.;
2499cfb853baSMatthew G. Knepley     bdt[d] = DM_BOUNDARY_PERIODIC;
2500cfb853baSMatthew G. Knepley   }
25018d2ec52aSSatish Balay   PetscCall(DMPlexCreateHypercubicMesh_Internal(*dm, dim, low, upp, edg, overlap, bdt));
2502cfb853baSMatthew G. Knepley   PetscCall(PetscFree4(edg, low, upp, bdt));
25033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2504cfb853baSMatthew G. Knepley }
2505cfb853baSMatthew G. Knepley 
2506cc4c1da9SBarry Smith /*@
2507a1cb98faSBarry Smith   DMPlexSetOptionsPrefix - Sets the prefix used for searching for all `DM` options in the database.
2508a9074c1eSMatthew G. Knepley 
250920f4b53cSBarry Smith   Logically Collective
2510a9074c1eSMatthew G. Knepley 
2511a9074c1eSMatthew G. Knepley   Input Parameters:
251220f4b53cSBarry Smith + dm     - the `DM` context
2513a9074c1eSMatthew G. Knepley - prefix - the prefix to prepend to all option names
2514a9074c1eSMatthew G. Knepley 
2515a1cb98faSBarry Smith   Level: advanced
2516a1cb98faSBarry Smith 
2517a1cb98faSBarry Smith   Note:
2518a9074c1eSMatthew G. Knepley   A hyphen (-) must NOT be given at the beginning of the prefix name.
2519a9074c1eSMatthew G. Knepley   The first character of all runtime options is AUTOMATICALLY the hyphen.
2520a9074c1eSMatthew G. Knepley 
25211cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `SNESSetFromOptions()`
2522a9074c1eSMatthew G. Knepley @*/
2523d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetOptionsPrefix(DM dm, const char prefix[])
2524d71ae5a4SJacob Faibussowitsch {
2525a9074c1eSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
2526a9074c1eSMatthew G. Knepley 
2527a9074c1eSMatthew G. Knepley   PetscFunctionBegin;
2528a9074c1eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25299566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
25309566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mesh->partitioner, prefix));
25313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2532a9074c1eSMatthew G. Knepley }
2533a9074c1eSMatthew G. Knepley 
25349318fe57SMatthew G. Knepley /* Remap geometry to cylinder
253561a622f3SMatthew G. Knepley    TODO: This only works for a single refinement, then it is broken
253661a622f3SMatthew G. Knepley 
25379318fe57SMatthew G. Knepley      Interior square: Linear interpolation is correct
25389318fe57SMatthew G. Knepley      The other cells all have vertices on rays from the origin. We want to uniformly expand the spacing
25399318fe57SMatthew G. Knepley      such that the last vertex is on the unit circle. So the closest and farthest vertices are at distance
25400510c589SMatthew G. Knepley 
25419318fe57SMatthew G. Knepley        phi     = arctan(y/x)
25429318fe57SMatthew G. Knepley        d_close = sqrt(1/8 + 1/4 sin^2(phi))
25439318fe57SMatthew G. Knepley        d_far   = sqrt(1/2 + sin^2(phi))
25440510c589SMatthew G. Knepley 
25459318fe57SMatthew G. Knepley      so we remap them using
25460510c589SMatthew G. Knepley 
25479318fe57SMatthew G. Knepley        x_new = x_close + (x - x_close) (1 - d_close) / (d_far - d_close)
25489318fe57SMatthew G. Knepley        y_new = y_close + (y - y_close) (1 - d_close) / (d_far - d_close)
25490510c589SMatthew G. Knepley 
25509318fe57SMatthew G. Knepley      If pi/4 < phi < 3pi/4 or -3pi/4 < phi < -pi/4, then we switch x and y.
25519318fe57SMatthew G. Knepley */
2552d71ae5a4SJacob Faibussowitsch static void snapToCylinder(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
2553d71ae5a4SJacob Faibussowitsch {
25549318fe57SMatthew G. Knepley   const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
25559318fe57SMatthew G. Knepley   const PetscReal ds2 = 0.5 * dis;
255622cc497dSMatthew G. Knepley 
25579318fe57SMatthew G. Knepley   if ((PetscAbsScalar(u[0]) <= ds2) && (PetscAbsScalar(u[1]) <= ds2)) {
25589318fe57SMatthew G. Knepley     f0[0] = u[0];
25599318fe57SMatthew G. Knepley     f0[1] = u[1];
25609318fe57SMatthew G. Knepley   } else {
25619318fe57SMatthew G. Knepley     PetscReal phi, sinp, cosp, dc, df, x, y, xc, yc;
25620510c589SMatthew G. Knepley 
25639318fe57SMatthew G. Knepley     x    = PetscRealPart(u[0]);
25649318fe57SMatthew G. Knepley     y    = PetscRealPart(u[1]);
25659318fe57SMatthew G. Knepley     phi  = PetscAtan2Real(y, x);
25669318fe57SMatthew G. Knepley     sinp = PetscSinReal(phi);
25679318fe57SMatthew G. Knepley     cosp = PetscCosReal(phi);
25689318fe57SMatthew G. Knepley     if ((PetscAbsReal(phi) > PETSC_PI / 4.0) && (PetscAbsReal(phi) < 3.0 * PETSC_PI / 4.0)) {
25699318fe57SMatthew G. Knepley       dc = PetscAbsReal(ds2 / sinp);
25709318fe57SMatthew G. Knepley       df = PetscAbsReal(dis / sinp);
25719318fe57SMatthew G. Knepley       xc = ds2 * x / PetscAbsReal(y);
25729318fe57SMatthew G. Knepley       yc = ds2 * PetscSignReal(y);
25739318fe57SMatthew G. Knepley     } else {
25749318fe57SMatthew G. Knepley       dc = PetscAbsReal(ds2 / cosp);
25759318fe57SMatthew G. Knepley       df = PetscAbsReal(dis / cosp);
25769318fe57SMatthew G. Knepley       xc = ds2 * PetscSignReal(x);
25779318fe57SMatthew G. Knepley       yc = ds2 * y / PetscAbsReal(x);
25789318fe57SMatthew G. Knepley     }
25799318fe57SMatthew G. Knepley     f0[0] = xc + (u[0] - xc) * (1.0 - dc) / (df - dc);
25809318fe57SMatthew G. Knepley     f0[1] = yc + (u[1] - yc) * (1.0 - dc) / (df - dc);
25819318fe57SMatthew G. Knepley   }
25829318fe57SMatthew G. Knepley   f0[2] = u[2];
25839318fe57SMatthew G. Knepley }
25840510c589SMatthew G. Knepley 
258549704ca5SMatthew G. Knepley static PetscErrorCode DMPlexCreateHexCylinderMesh_Internal(DM dm, DMBoundaryType periodicZ, PetscInt Nr)
2586d71ae5a4SJacob Faibussowitsch {
25870510c589SMatthew G. Knepley   const PetscInt dim = 3;
25889318fe57SMatthew G. Knepley   PetscInt       numCells, numVertices;
2589d8c47e87SMatthew G. Knepley   PetscMPIInt    rank;
25900510c589SMatthew G. Knepley 
25910510c589SMatthew G. Knepley   PetscFunctionBegin;
259246139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
25939566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
25949566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
25950510c589SMatthew G. Knepley   /* Create topology */
25960510c589SMatthew G. Knepley   {
25970510c589SMatthew G. Knepley     PetscInt cone[8], c;
25980510c589SMatthew G. Knepley 
2599dd400576SPatrick Sanan     numCells    = rank == 0 ? 5 : 0;
2600dd400576SPatrick Sanan     numVertices = rank == 0 ? 16 : 0;
2601006a8963SMatthew G. Knepley     if (periodicZ == DM_BOUNDARY_PERIODIC) {
2602ae8bcbbbSMatthew G. Knepley       numCells *= 3;
2603dd400576SPatrick Sanan       numVertices = rank == 0 ? 24 : 0;
2604006a8963SMatthew G. Knepley     }
26059566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
26069566063dSJacob Faibussowitsch     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 8));
26079566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm));
2608dd400576SPatrick Sanan     if (rank == 0) {
2609006a8963SMatthew G. Knepley       if (periodicZ == DM_BOUNDARY_PERIODIC) {
26109371c9d4SSatish Balay         cone[0] = 15;
26119371c9d4SSatish Balay         cone[1] = 18;
26129371c9d4SSatish Balay         cone[2] = 17;
26139371c9d4SSatish Balay         cone[3] = 16;
26149371c9d4SSatish Balay         cone[4] = 31;
26159371c9d4SSatish Balay         cone[5] = 32;
26169371c9d4SSatish Balay         cone[6] = 33;
26179371c9d4SSatish Balay         cone[7] = 34;
26189566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 0, cone));
26199371c9d4SSatish Balay         cone[0] = 16;
26209371c9d4SSatish Balay         cone[1] = 17;
26219371c9d4SSatish Balay         cone[2] = 24;
26229371c9d4SSatish Balay         cone[3] = 23;
26239371c9d4SSatish Balay         cone[4] = 32;
26249371c9d4SSatish Balay         cone[5] = 36;
26259371c9d4SSatish Balay         cone[6] = 37;
26269371c9d4SSatish Balay         cone[7] = 33; /* 22 25 26 21 */
26279566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 1, cone));
26289371c9d4SSatish Balay         cone[0] = 18;
26299371c9d4SSatish Balay         cone[1] = 27;
26309371c9d4SSatish Balay         cone[2] = 24;
26319371c9d4SSatish Balay         cone[3] = 17;
26329371c9d4SSatish Balay         cone[4] = 34;
26339371c9d4SSatish Balay         cone[5] = 33;
26349371c9d4SSatish Balay         cone[6] = 37;
26359371c9d4SSatish Balay         cone[7] = 38;
26369566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 2, cone));
26379371c9d4SSatish Balay         cone[0] = 29;
26389371c9d4SSatish Balay         cone[1] = 27;
26399371c9d4SSatish Balay         cone[2] = 18;
26409371c9d4SSatish Balay         cone[3] = 15;
26419371c9d4SSatish Balay         cone[4] = 35;
26429371c9d4SSatish Balay         cone[5] = 31;
26439371c9d4SSatish Balay         cone[6] = 34;
26449371c9d4SSatish Balay         cone[7] = 38;
26459566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 3, cone));
26469371c9d4SSatish Balay         cone[0] = 29;
26479371c9d4SSatish Balay         cone[1] = 15;
26489371c9d4SSatish Balay         cone[2] = 16;
26499371c9d4SSatish Balay         cone[3] = 23;
26509371c9d4SSatish Balay         cone[4] = 35;
26519371c9d4SSatish Balay         cone[5] = 36;
26529371c9d4SSatish Balay         cone[6] = 32;
26539371c9d4SSatish Balay         cone[7] = 31;
26549566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 4, cone));
2655006a8963SMatthew G. Knepley 
26569371c9d4SSatish Balay         cone[0] = 31;
26579371c9d4SSatish Balay         cone[1] = 34;
26589371c9d4SSatish Balay         cone[2] = 33;
26599371c9d4SSatish Balay         cone[3] = 32;
26609371c9d4SSatish Balay         cone[4] = 19;
26619371c9d4SSatish Balay         cone[5] = 22;
26629371c9d4SSatish Balay         cone[6] = 21;
26639371c9d4SSatish Balay         cone[7] = 20;
26649566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 5, cone));
26659371c9d4SSatish Balay         cone[0] = 32;
26669371c9d4SSatish Balay         cone[1] = 33;
26679371c9d4SSatish Balay         cone[2] = 37;
26689371c9d4SSatish Balay         cone[3] = 36;
26699371c9d4SSatish Balay         cone[4] = 22;
26709371c9d4SSatish Balay         cone[5] = 25;
26719371c9d4SSatish Balay         cone[6] = 26;
26729371c9d4SSatish Balay         cone[7] = 21;
26739566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 6, cone));
26749371c9d4SSatish Balay         cone[0] = 34;
26759371c9d4SSatish Balay         cone[1] = 38;
26769371c9d4SSatish Balay         cone[2] = 37;
26779371c9d4SSatish Balay         cone[3] = 33;
26789371c9d4SSatish Balay         cone[4] = 20;
26799371c9d4SSatish Balay         cone[5] = 21;
26809371c9d4SSatish Balay         cone[6] = 26;
26819371c9d4SSatish Balay         cone[7] = 28;
26829566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 7, cone));
26839371c9d4SSatish Balay         cone[0] = 35;
26849371c9d4SSatish Balay         cone[1] = 38;
26859371c9d4SSatish Balay         cone[2] = 34;
26869371c9d4SSatish Balay         cone[3] = 31;
26879371c9d4SSatish Balay         cone[4] = 30;
26889371c9d4SSatish Balay         cone[5] = 19;
26899371c9d4SSatish Balay         cone[6] = 20;
26909371c9d4SSatish Balay         cone[7] = 28;
26919566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 8, cone));
26929371c9d4SSatish Balay         cone[0] = 35;
26939371c9d4SSatish Balay         cone[1] = 31;
26949371c9d4SSatish Balay         cone[2] = 32;
26959371c9d4SSatish Balay         cone[3] = 36;
26969371c9d4SSatish Balay         cone[4] = 30;
26979371c9d4SSatish Balay         cone[5] = 25;
26989371c9d4SSatish Balay         cone[6] = 22;
26999371c9d4SSatish Balay         cone[7] = 19;
27009566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 9, cone));
2701ae8bcbbbSMatthew G. Knepley 
27029371c9d4SSatish Balay         cone[0] = 19;
27039371c9d4SSatish Balay         cone[1] = 20;
27049371c9d4SSatish Balay         cone[2] = 21;
27059371c9d4SSatish Balay         cone[3] = 22;
27069371c9d4SSatish Balay         cone[4] = 15;
27079371c9d4SSatish Balay         cone[5] = 16;
27089371c9d4SSatish Balay         cone[6] = 17;
27099371c9d4SSatish Balay         cone[7] = 18;
27109566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 10, cone));
27119371c9d4SSatish Balay         cone[0] = 22;
27129371c9d4SSatish Balay         cone[1] = 21;
27139371c9d4SSatish Balay         cone[2] = 26;
27149371c9d4SSatish Balay         cone[3] = 25;
27159371c9d4SSatish Balay         cone[4] = 16;
27169371c9d4SSatish Balay         cone[5] = 23;
27179371c9d4SSatish Balay         cone[6] = 24;
27189371c9d4SSatish Balay         cone[7] = 17;
27199566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 11, cone));
27209371c9d4SSatish Balay         cone[0] = 20;
27219371c9d4SSatish Balay         cone[1] = 28;
27229371c9d4SSatish Balay         cone[2] = 26;
27239371c9d4SSatish Balay         cone[3] = 21;
27249371c9d4SSatish Balay         cone[4] = 18;
27259371c9d4SSatish Balay         cone[5] = 17;
27269371c9d4SSatish Balay         cone[6] = 24;
27279371c9d4SSatish Balay         cone[7] = 27;
27289566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 12, cone));
27299371c9d4SSatish Balay         cone[0] = 30;
27309371c9d4SSatish Balay         cone[1] = 28;
27319371c9d4SSatish Balay         cone[2] = 20;
27329371c9d4SSatish Balay         cone[3] = 19;
27339371c9d4SSatish Balay         cone[4] = 29;
27349371c9d4SSatish Balay         cone[5] = 15;
27359371c9d4SSatish Balay         cone[6] = 18;
27369371c9d4SSatish Balay         cone[7] = 27;
27379566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 13, cone));
27389371c9d4SSatish Balay         cone[0] = 30;
27399371c9d4SSatish Balay         cone[1] = 19;
27409371c9d4SSatish Balay         cone[2] = 22;
27419371c9d4SSatish Balay         cone[3] = 25;
27429371c9d4SSatish Balay         cone[4] = 29;
27439371c9d4SSatish Balay         cone[5] = 23;
27449371c9d4SSatish Balay         cone[6] = 16;
27459371c9d4SSatish Balay         cone[7] = 15;
27469566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 14, cone));
2747006a8963SMatthew G. Knepley       } else {
27489371c9d4SSatish Balay         cone[0] = 5;
27499371c9d4SSatish Balay         cone[1] = 8;
27509371c9d4SSatish Balay         cone[2] = 7;
27519371c9d4SSatish Balay         cone[3] = 6;
27529371c9d4SSatish Balay         cone[4] = 9;
27539371c9d4SSatish Balay         cone[5] = 12;
27549371c9d4SSatish Balay         cone[6] = 11;
27559371c9d4SSatish Balay         cone[7] = 10;
27569566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 0, cone));
27579371c9d4SSatish Balay         cone[0] = 6;
27589371c9d4SSatish Balay         cone[1] = 7;
27599371c9d4SSatish Balay         cone[2] = 14;
27609371c9d4SSatish Balay         cone[3] = 13;
27619371c9d4SSatish Balay         cone[4] = 12;
27629371c9d4SSatish Balay         cone[5] = 15;
27639371c9d4SSatish Balay         cone[6] = 16;
27649371c9d4SSatish Balay         cone[7] = 11;
27659566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 1, cone));
27669371c9d4SSatish Balay         cone[0] = 8;
27679371c9d4SSatish Balay         cone[1] = 17;
27689371c9d4SSatish Balay         cone[2] = 14;
27699371c9d4SSatish Balay         cone[3] = 7;
27709371c9d4SSatish Balay         cone[4] = 10;
27719371c9d4SSatish Balay         cone[5] = 11;
27729371c9d4SSatish Balay         cone[6] = 16;
27739371c9d4SSatish Balay         cone[7] = 18;
27749566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 2, cone));
27759371c9d4SSatish Balay         cone[0] = 19;
27769371c9d4SSatish Balay         cone[1] = 17;
27779371c9d4SSatish Balay         cone[2] = 8;
27789371c9d4SSatish Balay         cone[3] = 5;
27799371c9d4SSatish Balay         cone[4] = 20;
27809371c9d4SSatish Balay         cone[5] = 9;
27819371c9d4SSatish Balay         cone[6] = 10;
27829371c9d4SSatish Balay         cone[7] = 18;
27839566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 3, cone));
27849371c9d4SSatish Balay         cone[0] = 19;
27859371c9d4SSatish Balay         cone[1] = 5;
27869371c9d4SSatish Balay         cone[2] = 6;
27879371c9d4SSatish Balay         cone[3] = 13;
27889371c9d4SSatish Balay         cone[4] = 20;
27899371c9d4SSatish Balay         cone[5] = 15;
27909371c9d4SSatish Balay         cone[6] = 12;
27919371c9d4SSatish Balay         cone[7] = 9;
27929566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 4, cone));
2793006a8963SMatthew G. Knepley       }
2794d8c47e87SMatthew G. Knepley     }
27959566063dSJacob Faibussowitsch     PetscCall(DMPlexSymmetrize(dm));
27969566063dSJacob Faibussowitsch     PetscCall(DMPlexStratify(dm));
27970510c589SMatthew G. Knepley   }
2798dbc1dc17SMatthew G. Knepley   /* Create cube geometry */
27990510c589SMatthew G. Knepley   {
28000510c589SMatthew G. Knepley     Vec             coordinates;
28010510c589SMatthew G. Knepley     PetscSection    coordSection;
28020510c589SMatthew G. Knepley     PetscScalar    *coords;
28030510c589SMatthew G. Knepley     PetscInt        coordSize, v;
28040510c589SMatthew G. Knepley     const PetscReal dis = 1.0 / PetscSqrtReal(2.0);
28050510c589SMatthew G. Knepley     const PetscReal ds2 = dis / 2.0;
28060510c589SMatthew G. Knepley 
28070510c589SMatthew G. Knepley     /* Build coordinates */
28089566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
28099566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(coordSection, 1));
28109566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
28119566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
28120510c589SMatthew G. Knepley     for (v = numCells; v < numCells + numVertices; ++v) {
28139566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(coordSection, v, dim));
28149566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
28150510c589SMatthew G. Knepley     }
28169566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(coordSection));
28179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
28189566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
28199566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
28209566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
28219566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(coordinates, dim));
28229566063dSJacob Faibussowitsch     PetscCall(VecSetType(coordinates, VECSTANDARD));
28239566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
2824dd400576SPatrick Sanan     if (rank == 0) {
28259371c9d4SSatish Balay       coords[0 * dim + 0]  = -ds2;
28269371c9d4SSatish Balay       coords[0 * dim + 1]  = -ds2;
28279371c9d4SSatish Balay       coords[0 * dim + 2]  = 0.0;
28289371c9d4SSatish Balay       coords[1 * dim + 0]  = ds2;
28299371c9d4SSatish Balay       coords[1 * dim + 1]  = -ds2;
28309371c9d4SSatish Balay       coords[1 * dim + 2]  = 0.0;
28319371c9d4SSatish Balay       coords[2 * dim + 0]  = ds2;
28329371c9d4SSatish Balay       coords[2 * dim + 1]  = ds2;
28339371c9d4SSatish Balay       coords[2 * dim + 2]  = 0.0;
28349371c9d4SSatish Balay       coords[3 * dim + 0]  = -ds2;
28359371c9d4SSatish Balay       coords[3 * dim + 1]  = ds2;
28369371c9d4SSatish Balay       coords[3 * dim + 2]  = 0.0;
28379371c9d4SSatish Balay       coords[4 * dim + 0]  = -ds2;
28389371c9d4SSatish Balay       coords[4 * dim + 1]  = -ds2;
28399371c9d4SSatish Balay       coords[4 * dim + 2]  = 1.0;
28409371c9d4SSatish Balay       coords[5 * dim + 0]  = -ds2;
28419371c9d4SSatish Balay       coords[5 * dim + 1]  = ds2;
28429371c9d4SSatish Balay       coords[5 * dim + 2]  = 1.0;
28439371c9d4SSatish Balay       coords[6 * dim + 0]  = ds2;
28449371c9d4SSatish Balay       coords[6 * dim + 1]  = ds2;
28459371c9d4SSatish Balay       coords[6 * dim + 2]  = 1.0;
28469371c9d4SSatish Balay       coords[7 * dim + 0]  = ds2;
28479371c9d4SSatish Balay       coords[7 * dim + 1]  = -ds2;
28489371c9d4SSatish Balay       coords[7 * dim + 2]  = 1.0;
28499371c9d4SSatish Balay       coords[8 * dim + 0]  = dis;
28509371c9d4SSatish Balay       coords[8 * dim + 1]  = -dis;
28519371c9d4SSatish Balay       coords[8 * dim + 2]  = 0.0;
28529371c9d4SSatish Balay       coords[9 * dim + 0]  = dis;
28539371c9d4SSatish Balay       coords[9 * dim + 1]  = dis;
28549371c9d4SSatish Balay       coords[9 * dim + 2]  = 0.0;
28559371c9d4SSatish Balay       coords[10 * dim + 0] = dis;
28569371c9d4SSatish Balay       coords[10 * dim + 1] = -dis;
28579371c9d4SSatish Balay       coords[10 * dim + 2] = 1.0;
28589371c9d4SSatish Balay       coords[11 * dim + 0] = dis;
28599371c9d4SSatish Balay       coords[11 * dim + 1] = dis;
28609371c9d4SSatish Balay       coords[11 * dim + 2] = 1.0;
28619371c9d4SSatish Balay       coords[12 * dim + 0] = -dis;
28629371c9d4SSatish Balay       coords[12 * dim + 1] = dis;
28639371c9d4SSatish Balay       coords[12 * dim + 2] = 0.0;
28649371c9d4SSatish Balay       coords[13 * dim + 0] = -dis;
28659371c9d4SSatish Balay       coords[13 * dim + 1] = dis;
28669371c9d4SSatish Balay       coords[13 * dim + 2] = 1.0;
28679371c9d4SSatish Balay       coords[14 * dim + 0] = -dis;
28689371c9d4SSatish Balay       coords[14 * dim + 1] = -dis;
28699371c9d4SSatish Balay       coords[14 * dim + 2] = 0.0;
28709371c9d4SSatish Balay       coords[15 * dim + 0] = -dis;
28719371c9d4SSatish Balay       coords[15 * dim + 1] = -dis;
28729371c9d4SSatish Balay       coords[15 * dim + 2] = 1.0;
2873ae8bcbbbSMatthew G. Knepley       if (periodicZ == DM_BOUNDARY_PERIODIC) {
28749371c9d4SSatish Balay         /* 15 31 19 */ coords[16 * dim + 0] = -ds2;
28759371c9d4SSatish Balay         coords[16 * dim + 1]                = -ds2;
28769371c9d4SSatish Balay         coords[16 * dim + 2]                = 0.5;
28779371c9d4SSatish Balay         /* 16 32 22 */ coords[17 * dim + 0] = ds2;
28789371c9d4SSatish Balay         coords[17 * dim + 1]                = -ds2;
28799371c9d4SSatish Balay         coords[17 * dim + 2]                = 0.5;
28809371c9d4SSatish Balay         /* 17 33 21 */ coords[18 * dim + 0] = ds2;
28819371c9d4SSatish Balay         coords[18 * dim + 1]                = ds2;
28829371c9d4SSatish Balay         coords[18 * dim + 2]                = 0.5;
28839371c9d4SSatish Balay         /* 18 34 20 */ coords[19 * dim + 0] = -ds2;
28849371c9d4SSatish Balay         coords[19 * dim + 1]                = ds2;
28859371c9d4SSatish Balay         coords[19 * dim + 2]                = 0.5;
28869371c9d4SSatish Balay         /* 29 35 30 */ coords[20 * dim + 0] = -dis;
28879371c9d4SSatish Balay         coords[20 * dim + 1]                = -dis;
28889371c9d4SSatish Balay         coords[20 * dim + 2]                = 0.5;
28899371c9d4SSatish Balay         /* 23 36 25 */ coords[21 * dim + 0] = dis;
28909371c9d4SSatish Balay         coords[21 * dim + 1]                = -dis;
28919371c9d4SSatish Balay         coords[21 * dim + 2]                = 0.5;
28929371c9d4SSatish Balay         /* 24 37 26 */ coords[22 * dim + 0] = dis;
28939371c9d4SSatish Balay         coords[22 * dim + 1]                = dis;
28949371c9d4SSatish Balay         coords[22 * dim + 2]                = 0.5;
28959371c9d4SSatish Balay         /* 27 38 28 */ coords[23 * dim + 0] = -dis;
28969371c9d4SSatish Balay         coords[23 * dim + 1]                = dis;
28979371c9d4SSatish Balay         coords[23 * dim + 2]                = 0.5;
2898ae8bcbbbSMatthew G. Knepley       }
2899d8c47e87SMatthew G. Knepley     }
29009566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
29019566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
29029566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&coordinates));
29030510c589SMatthew G. Knepley   }
2904006a8963SMatthew G. Knepley   /* Create periodicity */
2905006a8963SMatthew G. Knepley   if (periodicZ == DM_BOUNDARY_PERIODIC || periodicZ == DM_BOUNDARY_TWIST) {
29066858538eSMatthew G. Knepley     PetscReal L[3]       = {-1., -1., 0.};
29076858538eSMatthew G. Knepley     PetscReal maxCell[3] = {-1., -1., 0.};
2908006a8963SMatthew G. Knepley     PetscReal lower[3]   = {0.0, 0.0, 0.0};
2909ae8bcbbbSMatthew G. Knepley     PetscReal upper[3]   = {1.0, 1.0, 1.5};
29106858538eSMatthew G. Knepley     PetscInt  numZCells  = 3;
2911006a8963SMatthew G. Knepley 
29126858538eSMatthew G. Knepley     L[2]       = upper[2] - lower[2];
29136858538eSMatthew G. Knepley     maxCell[2] = 1.1 * (L[2] / numZCells);
29144fb89dddSMatthew G. Knepley     PetscCall(DMSetPeriodicity(dm, maxCell, lower, L));
2915006a8963SMatthew G. Knepley   }
2916dbc1dc17SMatthew G. Knepley   {
29179318fe57SMatthew G. Knepley     DM          cdm;
29189318fe57SMatthew G. Knepley     PetscDS     cds;
29199318fe57SMatthew G. Knepley     PetscScalar c[2] = {1.0, 1.0};
2920dbc1dc17SMatthew G. Knepley 
2921e65c294aSksagiyam     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
29229566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(dm, &cdm));
29239566063dSJacob Faibussowitsch     PetscCall(DMGetDS(cdm, &cds));
29249566063dSJacob Faibussowitsch     PetscCall(PetscDSSetConstants(cds, 2, c));
2925dbc1dc17SMatthew G. Knepley   }
292646139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
292746139095SJed Brown 
29289318fe57SMatthew G. Knepley   /* Wait for coordinate creation before doing in-place modification */
29299566063dSJacob Faibussowitsch   PetscCall(DMPlexInterpolateInPlace_Internal(dm));
293049704ca5SMatthew G. Knepley 
293149704ca5SMatthew G. Knepley   char        oldprefix[PETSC_MAX_PATH_LEN];
293249704ca5SMatthew G. Knepley   const char *prefix;
293349704ca5SMatthew G. Knepley 
293449704ca5SMatthew G. Knepley   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
293549704ca5SMatthew G. Knepley   PetscCall(PetscStrncpy(oldprefix, prefix, PETSC_MAX_PATH_LEN));
293649704ca5SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, "petsc_cyl_ref_"));
293749704ca5SMatthew G. Knepley   for (PetscInt r = 0; r < PetscMax(0, Nr); ++r) {
293849704ca5SMatthew G. Knepley     DM rdm;
293949704ca5SMatthew G. Knepley 
294049704ca5SMatthew G. Knepley     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
294149704ca5SMatthew G. Knepley     PetscCall(DMPlexReplace_Internal(dm, &rdm));
294249704ca5SMatthew G. Knepley   }
294349704ca5SMatthew G. Knepley   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldprefix));
294449704ca5SMatthew G. Knepley   PetscCall(DMPlexRemapGeometry(dm, 0.0, snapToCylinder));
294549704ca5SMatthew G. Knepley 
294649704ca5SMatthew G. Knepley   DMLabel         bdlabel, edgelabel;
294749704ca5SMatthew G. Knepley   IS              faceIS;
294849704ca5SMatthew G. Knepley   const PetscInt *faces;
294949704ca5SMatthew G. Knepley   PetscInt        Nf;
295049704ca5SMatthew G. Knepley 
295149704ca5SMatthew G. Knepley   PetscCall(DMCreateLabel(dm, "marker"));
295249704ca5SMatthew G. Knepley   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
295349704ca5SMatthew G. Knepley   PetscCall(DMCreateLabel(dm, "generatrix"));
295449704ca5SMatthew G. Knepley   PetscCall(DMGetLabel(dm, "generatrix", &edgelabel));
295549704ca5SMatthew G. Knepley   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
295649704ca5SMatthew G. Knepley   // Remove faces on top and bottom
295749704ca5SMatthew G. Knepley   PetscCall(DMLabelGetStratumIS(bdlabel, 1, &faceIS));
2958ba1b3593SJeremy L Thompson   if (faceIS) {
295949704ca5SMatthew G. Knepley     PetscCall(ISGetLocalSize(faceIS, &Nf));
296049704ca5SMatthew G. Knepley     PetscCall(ISGetIndices(faceIS, &faces));
296149704ca5SMatthew G. Knepley     for (PetscInt f = 0; f < Nf; ++f) {
296249704ca5SMatthew G. Knepley       PetscReal vol, normal[3];
296349704ca5SMatthew G. Knepley 
296449704ca5SMatthew G. Knepley       PetscCall(DMPlexComputeCellGeometryFVM(dm, faces[f], &vol, NULL, normal));
296549704ca5SMatthew G. Knepley       if (PetscAbsReal(normal[2]) < PETSC_SMALL) PetscCall(DMLabelSetValue(edgelabel, faces[f], 1));
296649704ca5SMatthew G. Knepley     }
296749704ca5SMatthew G. Knepley     PetscCall(ISRestoreIndices(faceIS, &faces));
296849704ca5SMatthew G. Knepley     PetscCall(ISDestroy(&faceIS));
2969ba1b3593SJeremy L Thompson   }
297049704ca5SMatthew G. Knepley   PetscCall(DMPlexLabelComplete(dm, bdlabel));
297149704ca5SMatthew G. Knepley   PetscCall(DMPlexLabelComplete(dm, edgelabel));
29723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29730510c589SMatthew G. Knepley }
29740510c589SMatthew G. Knepley 
297524119c2aSMatthew G. Knepley /*@
29769318fe57SMatthew G. Knepley   DMPlexCreateHexCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using hexahedra.
297724119c2aSMatthew G. Knepley 
2978d083f849SBarry Smith   Collective
297924119c2aSMatthew G. Knepley 
298024119c2aSMatthew G. Knepley   Input Parameters:
2981a1cb98faSBarry Smith + comm      - The communicator for the `DM` object
298249704ca5SMatthew G. Knepley . periodicZ - The boundary type for the Z direction
298349704ca5SMatthew G. Knepley - Nr        - The number of refinements to carry out
298424119c2aSMatthew G. Knepley 
298524119c2aSMatthew G. Knepley   Output Parameter:
298620f4b53cSBarry Smith . dm - The `DM` object
298724119c2aSMatthew G. Knepley 
298824119c2aSMatthew G. Knepley   Level: beginner
298924119c2aSMatthew G. Knepley 
2990a1cb98faSBarry Smith   Note:
2991a4e35b19SJacob Faibussowitsch   Here is the output numbering looking from the bottom of the cylinder\:
2992a1cb98faSBarry Smith .vb
2993a1cb98faSBarry Smith        17-----14
2994a1cb98faSBarry Smith         |     |
2995a1cb98faSBarry Smith         |  2  |
2996a1cb98faSBarry Smith         |     |
2997a1cb98faSBarry Smith  17-----8-----7-----14
2998a1cb98faSBarry Smith   |     |     |     |
2999a1cb98faSBarry Smith   |  3  |  0  |  1  |
3000a1cb98faSBarry Smith   |     |     |     |
3001a1cb98faSBarry Smith  19-----5-----6-----13
3002a1cb98faSBarry Smith         |     |
3003a1cb98faSBarry Smith         |  4  |
3004a1cb98faSBarry Smith         |     |
3005a1cb98faSBarry Smith        19-----13
3006a1cb98faSBarry Smith 
3007a1cb98faSBarry Smith  and up through the top
3008a1cb98faSBarry Smith 
3009a1cb98faSBarry Smith        18-----16
3010a1cb98faSBarry Smith         |     |
3011a1cb98faSBarry Smith         |  2  |
3012a1cb98faSBarry Smith         |     |
3013a1cb98faSBarry Smith  18----10----11-----16
3014a1cb98faSBarry Smith   |     |     |     |
3015a1cb98faSBarry Smith   |  3  |  0  |  1  |
3016a1cb98faSBarry Smith   |     |     |     |
3017a1cb98faSBarry Smith  20-----9----12-----15
3018a1cb98faSBarry Smith         |     |
3019a1cb98faSBarry Smith         |  4  |
3020a1cb98faSBarry Smith         |     |
3021a1cb98faSBarry Smith        20-----15
3022a1cb98faSBarry Smith .ve
3023a1cb98faSBarry Smith 
30241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
302524119c2aSMatthew G. Knepley @*/
302649704ca5SMatthew G. Knepley PetscErrorCode DMPlexCreateHexCylinderMesh(MPI_Comm comm, DMBoundaryType periodicZ, PetscInt Nr, DM *dm)
3027d71ae5a4SJacob Faibussowitsch {
30289318fe57SMatthew G. Knepley   PetscFunctionBegin;
302949704ca5SMatthew G. Knepley   PetscAssertPointer(dm, 4);
30309566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
30319566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
303249704ca5SMatthew G. Knepley   PetscCall(DMPlexCreateHexCylinderMesh_Internal(*dm, periodicZ, Nr));
30333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30349318fe57SMatthew G. Knepley }
30359318fe57SMatthew G. Knepley 
3036d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateWedgeCylinderMesh_Internal(DM dm, PetscInt n, PetscBool interpolate)
3037d71ae5a4SJacob Faibussowitsch {
303824119c2aSMatthew G. Knepley   const PetscInt dim = 3;
3039412e9a14SMatthew G. Knepley   PetscInt       numCells, numVertices, v;
30409fe9f049SMatthew G. Knepley   PetscMPIInt    rank;
304124119c2aSMatthew G. Knepley 
304224119c2aSMatthew G. Knepley   PetscFunctionBegin;
304363a3b9bcSJacob Faibussowitsch   PetscCheck(n >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of wedges %" PetscInt_FMT " cannot be negative", n);
304446139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
30459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
30469566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
3047412e9a14SMatthew G. Knepley   /* Must create the celltype label here so that we do not automatically try to compute the types */
30489566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "celltype"));
304924119c2aSMatthew G. Knepley   /* Create topology */
305024119c2aSMatthew G. Knepley   {
305124119c2aSMatthew G. Knepley     PetscInt cone[6], c;
305224119c2aSMatthew G. Knepley 
3053dd400576SPatrick Sanan     numCells    = rank == 0 ? n : 0;
3054dd400576SPatrick Sanan     numVertices = rank == 0 ? 2 * (n + 1) : 0;
30559566063dSJacob Faibussowitsch     PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
30569566063dSJacob Faibussowitsch     for (c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 6));
30579566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dm));
305824119c2aSMatthew G. Knepley     for (c = 0; c < numCells; c++) {
30599371c9d4SSatish Balay       cone[0] = c + n * 1;
30609371c9d4SSatish Balay       cone[1] = (c + 1) % n + n * 1;
30619371c9d4SSatish Balay       cone[2] = 0 + 3 * n;
30629371c9d4SSatish Balay       cone[3] = c + n * 2;
30639371c9d4SSatish Balay       cone[4] = (c + 1) % n + n * 2;
30649371c9d4SSatish Balay       cone[5] = 1 + 3 * n;
30659566063dSJacob Faibussowitsch       PetscCall(DMPlexSetCone(dm, c, cone));
30669566063dSJacob Faibussowitsch       PetscCall(DMPlexSetCellType(dm, c, DM_POLYTOPE_TRI_PRISM_TENSOR));
306724119c2aSMatthew G. Knepley     }
30689566063dSJacob Faibussowitsch     PetscCall(DMPlexSymmetrize(dm));
30699566063dSJacob Faibussowitsch     PetscCall(DMPlexStratify(dm));
307024119c2aSMatthew G. Knepley   }
307148a46eb9SPierre Jolivet   for (v = numCells; v < numCells + numVertices; ++v) PetscCall(DMPlexSetCellType(dm, v, DM_POLYTOPE_POINT));
307224119c2aSMatthew G. Knepley   /* Create cylinder geometry */
307324119c2aSMatthew G. Knepley   {
307424119c2aSMatthew G. Knepley     Vec          coordinates;
307524119c2aSMatthew G. Knepley     PetscSection coordSection;
307624119c2aSMatthew G. Knepley     PetscScalar *coords;
3077412e9a14SMatthew G. Knepley     PetscInt     coordSize, c;
307824119c2aSMatthew G. Knepley 
307924119c2aSMatthew G. Knepley     /* Build coordinates */
30809566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSection));
30819566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(coordSection, 1));
30829566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dim));
30839566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(coordSection, numCells, numCells + numVertices));
308424119c2aSMatthew G. Knepley     for (v = numCells; v < numCells + numVertices; ++v) {
30859566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(coordSection, v, dim));
30869566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dim));
308724119c2aSMatthew G. Knepley     }
30889566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(coordSection));
30899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
30909566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
30919566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
30929566063dSJacob Faibussowitsch     PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
30939566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(coordinates, dim));
30949566063dSJacob Faibussowitsch     PetscCall(VecSetType(coordinates, VECSTANDARD));
30959566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
309624119c2aSMatthew G. Knepley     for (c = 0; c < numCells; c++) {
30979371c9d4SSatish Balay       coords[(c + 0 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
30989371c9d4SSatish Balay       coords[(c + 0 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
30999371c9d4SSatish Balay       coords[(c + 0 * n) * dim + 2] = 1.0;
31009371c9d4SSatish Balay       coords[(c + 1 * n) * dim + 0] = PetscCosReal(2.0 * c * PETSC_PI / n);
31019371c9d4SSatish Balay       coords[(c + 1 * n) * dim + 1] = PetscSinReal(2.0 * c * PETSC_PI / n);
31029371c9d4SSatish Balay       coords[(c + 1 * n) * dim + 2] = 0.0;
310324119c2aSMatthew G. Knepley     }
3104dd400576SPatrick Sanan     if (rank == 0) {
31059371c9d4SSatish Balay       coords[(2 * n + 0) * dim + 0] = 0.0;
31069371c9d4SSatish Balay       coords[(2 * n + 0) * dim + 1] = 0.0;
31079371c9d4SSatish Balay       coords[(2 * n + 0) * dim + 2] = 1.0;
31089371c9d4SSatish Balay       coords[(2 * n + 1) * dim + 0] = 0.0;
31099371c9d4SSatish Balay       coords[(2 * n + 1) * dim + 1] = 0.0;
31109371c9d4SSatish Balay       coords[(2 * n + 1) * dim + 2] = 0.0;
31119fe9f049SMatthew G. Knepley     }
31129566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(coordinates, &coords));
31139566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinatesLocal(dm, coordinates));
31149566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&coordinates));
311524119c2aSMatthew G. Knepley   }
311646139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
31179318fe57SMatthew G. Knepley   /* Interpolate */
31189566063dSJacob Faibussowitsch   if (interpolate) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
31193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31209318fe57SMatthew G. Knepley }
31219318fe57SMatthew G. Knepley 
31229318fe57SMatthew G. Knepley /*@
31239318fe57SMatthew G. Knepley   DMPlexCreateWedgeCylinderMesh - Creates a mesh on the tensor product of the unit interval with the circle (cylinder) using wedges.
31249318fe57SMatthew G. Knepley 
31259318fe57SMatthew G. Knepley   Collective
31269318fe57SMatthew G. Knepley 
31279318fe57SMatthew G. Knepley   Input Parameters:
3128a1cb98faSBarry Smith + comm        - The communicator for the `DM` object
31299318fe57SMatthew G. Knepley . n           - The number of wedges around the origin
31309318fe57SMatthew G. Knepley - interpolate - Create edges and faces
31319318fe57SMatthew G. Knepley 
31329318fe57SMatthew G. Knepley   Output Parameter:
3133a1cb98faSBarry Smith . dm - The `DM` object
31349318fe57SMatthew G. Knepley 
31359318fe57SMatthew G. Knepley   Level: beginner
31369318fe57SMatthew G. Knepley 
31371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateHexCylinderMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
31389318fe57SMatthew G. Knepley @*/
3139d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateWedgeCylinderMesh(MPI_Comm comm, PetscInt n, PetscBool interpolate, DM *dm)
3140d71ae5a4SJacob Faibussowitsch {
31419318fe57SMatthew G. Knepley   PetscFunctionBegin;
31424f572ea9SToby Isaac   PetscAssertPointer(dm, 4);
31439566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
31449566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
31459566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(*dm, n, interpolate));
31463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
314724119c2aSMatthew G. Knepley }
314824119c2aSMatthew G. Knepley 
3149d71ae5a4SJacob Faibussowitsch static inline PetscReal DiffNormReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
3150d71ae5a4SJacob Faibussowitsch {
315165a81367SMatthew G. Knepley   PetscReal prod = 0.0;
315265a81367SMatthew G. Knepley   PetscInt  i;
315365a81367SMatthew G. Knepley   for (i = 0; i < dim; ++i) prod += PetscSqr(x[i] - y[i]);
315465a81367SMatthew G. Knepley   return PetscSqrtReal(prod);
315565a81367SMatthew G. Knepley }
3156dd2b43ebSStefano Zampini 
3157d71ae5a4SJacob Faibussowitsch static inline PetscReal DotReal(PetscInt dim, const PetscReal x[], const PetscReal y[])
3158d71ae5a4SJacob Faibussowitsch {
315965a81367SMatthew G. Knepley   PetscReal prod = 0.0;
316065a81367SMatthew G. Knepley   PetscInt  i;
316165a81367SMatthew G. Knepley   for (i = 0; i < dim; ++i) prod += x[i] * y[i];
316265a81367SMatthew G. Knepley   return prod;
316365a81367SMatthew G. Knepley }
316465a81367SMatthew G. Knepley 
316551a74b61SMatthew G. Knepley /* The first constant is the sphere radius */
3166d71ae5a4SJacob Faibussowitsch static void snapToSphere(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
3167d71ae5a4SJacob Faibussowitsch {
316851a74b61SMatthew G. Knepley   PetscReal r     = PetscRealPart(constants[0]);
316951a74b61SMatthew G. Knepley   PetscReal norm2 = 0.0, fac;
317051a74b61SMatthew G. Knepley   PetscInt  n     = uOff[1] - uOff[0], d;
317151a74b61SMatthew G. Knepley 
317251a74b61SMatthew G. Knepley   for (d = 0; d < n; ++d) norm2 += PetscSqr(PetscRealPart(u[d]));
317351a74b61SMatthew G. Knepley   fac = r / PetscSqrtReal(norm2);
317451a74b61SMatthew G. Knepley   for (d = 0; d < n; ++d) f0[d] = u[d] * fac;
317551a74b61SMatthew G. Knepley }
317651a74b61SMatthew G. Knepley 
3177d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateSphereMesh_Internal(DM dm, PetscInt dim, PetscBool simplex, PetscReal R)
3178d71ae5a4SJacob Faibussowitsch {
317965a81367SMatthew G. Knepley   const PetscInt embedDim = dim + 1;
318065a81367SMatthew G. Knepley   PetscSection   coordSection;
318165a81367SMatthew G. Knepley   Vec            coordinates;
318265a81367SMatthew G. Knepley   PetscScalar   *coords;
318365a81367SMatthew G. Knepley   PetscReal     *coordsIn;
318407c565c5SJose E. Roman   PetscInt       numCells, numEdges, numVerts = 0, firstVertex = 0, v, firstEdge, coordSize, d, e;
318565a81367SMatthew G. Knepley   PetscMPIInt    rank;
318665a81367SMatthew G. Knepley 
318765a81367SMatthew G. Knepley   PetscFunctionBegin;
31889318fe57SMatthew G. Knepley   PetscValidLogicalCollectiveBool(dm, simplex, 3);
318946139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
31909566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, dim));
31919566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, dim + 1));
31929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
319365a81367SMatthew G. Knepley   switch (dim) {
31945c344501SMatthew G. Knepley   case 1:
31955c344501SMatthew G. Knepley     numCells = 16;
31965c344501SMatthew G. Knepley     numVerts = numCells;
31975c344501SMatthew G. Knepley 
31985c344501SMatthew G. Knepley     // Build Topology
31995c344501SMatthew G. Knepley     PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
32005c344501SMatthew G. Knepley     for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
32015c344501SMatthew G. Knepley     PetscCall(DMSetUp(dm));
32025c344501SMatthew G. Knepley     for (PetscInt c = 0; c < numCells; ++c) {
32035c344501SMatthew G. Knepley       PetscInt cone[2];
32045c344501SMatthew G. Knepley 
32055c344501SMatthew G. Knepley       cone[0] = c + numCells;
32065c344501SMatthew G. Knepley       cone[1] = (c + 1) % numVerts + numCells;
32075c344501SMatthew G. Knepley       PetscCall(DMPlexSetCone(dm, c, cone));
32085c344501SMatthew G. Knepley     }
32095c344501SMatthew G. Knepley     PetscCall(DMPlexSymmetrize(dm));
32105c344501SMatthew G. Knepley     PetscCall(DMPlexStratify(dm));
32115c344501SMatthew G. Knepley     PetscCall(PetscMalloc1(numVerts * embedDim, &coordsIn));
32125c344501SMatthew G. Knepley     for (PetscInt v = 0; v < numVerts; ++v) {
32135c344501SMatthew G. Knepley       const PetscReal rad = 2. * PETSC_PI * v / numVerts;
32145c344501SMatthew G. Knepley 
32155c344501SMatthew G. Knepley       coordsIn[v * embedDim + 0] = PetscCosReal(rad);
32165c344501SMatthew G. Knepley       coordsIn[v * embedDim + 1] = PetscSinReal(rad);
32175c344501SMatthew G. Knepley     }
32185c344501SMatthew G. Knepley     break;
321965a81367SMatthew G. Knepley   case 2:
322065a81367SMatthew G. Knepley     if (simplex) {
322151a74b61SMatthew G. Knepley       const PetscReal radius    = PetscSqrtReal(1 + PETSC_PHI * PETSC_PHI) / (1.0 + PETSC_PHI);
322251a74b61SMatthew G. Knepley       const PetscReal edgeLen   = 2.0 / (1.0 + PETSC_PHI) * (R / radius);
322365a81367SMatthew G. Knepley       const PetscInt  degree    = 5;
322451a74b61SMatthew G. Knepley       PetscReal       vertex[3] = {0.0, 1.0 / (1.0 + PETSC_PHI), PETSC_PHI / (1.0 + PETSC_PHI)};
322565a81367SMatthew G. Knepley       PetscInt        s[3]      = {1, 1, 1};
322665a81367SMatthew G. Knepley       PetscInt        cone[3];
322707c565c5SJose E. Roman       PetscInt       *graph;
322865a81367SMatthew G. Knepley 
32299371c9d4SSatish Balay       vertex[0] *= R / radius;
32309371c9d4SSatish Balay       vertex[1] *= R / radius;
32319371c9d4SSatish Balay       vertex[2] *= R / radius;
3232dd400576SPatrick Sanan       numCells    = rank == 0 ? 20 : 0;
3233dd400576SPatrick Sanan       numVerts    = rank == 0 ? 12 : 0;
323465a81367SMatthew G. Knepley       firstVertex = numCells;
323551a74b61SMatthew G. Knepley       /* Use icosahedron, which for a R-sphere has coordinates which are all cyclic permutations of
323665a81367SMatthew G. Knepley 
323765a81367SMatthew G. Knepley            (0, \pm 1/\phi+1, \pm \phi/\phi+1)
323865a81367SMatthew G. Knepley 
323965a81367SMatthew G. Knepley          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
324051a74b61SMatthew G. Knepley          length is then given by 2/(1+\phi) = 2 * 0.38197 = 0.76393.
324165a81367SMatthew G. Knepley       */
324265a81367SMatthew G. Knepley       /* Construct vertices */
32439566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3244dd400576SPatrick Sanan       if (rank == 0) {
324507c565c5SJose E. Roman         for (PetscInt p = 0, i = 0; p < embedDim; ++p) {
324665a81367SMatthew G. Knepley           for (s[1] = -1; s[1] < 2; s[1] += 2) {
324765a81367SMatthew G. Knepley             for (s[2] = -1; s[2] < 2; s[2] += 2) {
324865a81367SMatthew G. Knepley               for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertex[(d + p) % embedDim];
324965a81367SMatthew G. Knepley               ++i;
325065a81367SMatthew G. Knepley             }
325165a81367SMatthew G. Knepley           }
325265a81367SMatthew G. Knepley         }
325345da822fSValeria Barra       }
325465a81367SMatthew G. Knepley       /* Construct graph */
32559566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
325607c565c5SJose E. Roman       for (PetscInt i = 0; i < numVerts; ++i) {
325707c565c5SJose E. Roman         PetscInt k = 0;
325807c565c5SJose E. Roman         for (PetscInt j = 0; j < numVerts; ++j) {
32599371c9d4SSatish Balay           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
32609371c9d4SSatish Balay             graph[i * numVerts + j] = 1;
32619371c9d4SSatish Balay             ++k;
32629371c9d4SSatish Balay           }
326365a81367SMatthew G. Knepley         }
326463a3b9bcSJacob Faibussowitsch         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid icosahedron, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
326565a81367SMatthew G. Knepley       }
326665a81367SMatthew G. Knepley       /* Build Topology */
32679566063dSJacob Faibussowitsch       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
326807c565c5SJose E. Roman       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
32699566063dSJacob Faibussowitsch       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
327065a81367SMatthew G. Knepley       /* Cells */
327107c565c5SJose E. Roman       for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
327207c565c5SJose E. Roman         for (PetscInt j = 0; j < i; ++j) {
327307c565c5SJose E. Roman           for (PetscInt k = 0; k < j; ++k) {
327465a81367SMatthew G. Knepley             if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i]) {
32759371c9d4SSatish Balay               cone[0] = firstVertex + i;
32769371c9d4SSatish Balay               cone[1] = firstVertex + j;
32779371c9d4SSatish Balay               cone[2] = firstVertex + k;
327865a81367SMatthew G. Knepley               /* Check orientation */
327965a81367SMatthew G. Knepley               {
32809371c9d4SSatish Balay                 const PetscInt epsilon[3][3][3] = {
32819371c9d4SSatish Balay                   {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
32829371c9d4SSatish Balay                   {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
32839371c9d4SSatish Balay                   {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
32849371c9d4SSatish Balay                 };
328565a81367SMatthew G. Knepley                 PetscReal normal[3];
328665a81367SMatthew G. Knepley                 PetscInt  e, f;
328765a81367SMatthew G. Knepley 
328865a81367SMatthew G. Knepley                 for (d = 0; d < embedDim; ++d) {
328965a81367SMatthew G. Knepley                   normal[d] = 0.0;
329065a81367SMatthew G. Knepley                   for (e = 0; e < embedDim; ++e) {
3291ad540459SPierre Jolivet                     for (f = 0; f < embedDim; ++f) normal[d] += epsilon[d][e][f] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]);
329265a81367SMatthew G. Knepley                   }
329365a81367SMatthew G. Knepley                 }
32949371c9d4SSatish Balay                 if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
32959371c9d4SSatish Balay                   PetscInt tmp = cone[1];
32969371c9d4SSatish Balay                   cone[1]      = cone[2];
32979371c9d4SSatish Balay                   cone[2]      = tmp;
329865a81367SMatthew G. Knepley                 }
329965a81367SMatthew G. Knepley               }
33009566063dSJacob Faibussowitsch               PetscCall(DMPlexSetCone(dm, c++, cone));
330165a81367SMatthew G. Knepley             }
330265a81367SMatthew G. Knepley           }
330365a81367SMatthew G. Knepley         }
330465a81367SMatthew G. Knepley       }
33059566063dSJacob Faibussowitsch       PetscCall(DMPlexSymmetrize(dm));
33069566063dSJacob Faibussowitsch       PetscCall(DMPlexStratify(dm));
33079566063dSJacob Faibussowitsch       PetscCall(PetscFree(graph));
330865a81367SMatthew G. Knepley     } else {
33092829fed8SMatthew G. Knepley       /*
33102829fed8SMatthew G. Knepley         12-21--13
33112829fed8SMatthew G. Knepley          |     |
33122829fed8SMatthew G. Knepley         25  4  24
33132829fed8SMatthew G. Knepley          |     |
33142829fed8SMatthew G. Knepley   12-25--9-16--8-24--13
33152829fed8SMatthew G. Knepley    |     |     |     |
33162829fed8SMatthew G. Knepley   23  5 17  0 15  3  22
33172829fed8SMatthew G. Knepley    |     |     |     |
33182829fed8SMatthew G. Knepley   10-20--6-14--7-19--11
33192829fed8SMatthew G. Knepley          |     |
33202829fed8SMatthew G. Knepley         20  1  19
33212829fed8SMatthew G. Knepley          |     |
33222829fed8SMatthew G. Knepley         10-18--11
33232829fed8SMatthew G. Knepley          |     |
33242829fed8SMatthew G. Knepley         23  2  22
33252829fed8SMatthew G. Knepley          |     |
33262829fed8SMatthew G. Knepley         12-21--13
33272829fed8SMatthew G. Knepley        */
33282829fed8SMatthew G. Knepley       PetscInt cone[4], ornt[4];
33292829fed8SMatthew G. Knepley 
3330dd400576SPatrick Sanan       numCells    = rank == 0 ? 6 : 0;
3331dd400576SPatrick Sanan       numEdges    = rank == 0 ? 12 : 0;
3332dd400576SPatrick Sanan       numVerts    = rank == 0 ? 8 : 0;
333365a81367SMatthew G. Knepley       firstVertex = numCells;
333465a81367SMatthew G. Knepley       firstEdge   = numCells + numVerts;
33352829fed8SMatthew G. Knepley       /* Build Topology */
33369566063dSJacob Faibussowitsch       PetscCall(DMPlexSetChart(dm, 0, numCells + numEdges + numVerts));
333707c565c5SJose E. Roman       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, 4));
333848a46eb9SPierre Jolivet       for (e = firstEdge; e < firstEdge + numEdges; ++e) PetscCall(DMPlexSetConeSize(dm, e, 2));
33399566063dSJacob Faibussowitsch       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
3340dd400576SPatrick Sanan       if (rank == 0) {
33412829fed8SMatthew G. Knepley         /* Cell 0 */
33429371c9d4SSatish Balay         cone[0] = 14;
33439371c9d4SSatish Balay         cone[1] = 15;
33449371c9d4SSatish Balay         cone[2] = 16;
33459371c9d4SSatish Balay         cone[3] = 17;
33469566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 0, cone));
33479371c9d4SSatish Balay         ornt[0] = 0;
33489371c9d4SSatish Balay         ornt[1] = 0;
33499371c9d4SSatish Balay         ornt[2] = 0;
33509371c9d4SSatish Balay         ornt[3] = 0;
33519566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 0, ornt));
33522829fed8SMatthew G. Knepley         /* Cell 1 */
33539371c9d4SSatish Balay         cone[0] = 18;
33549371c9d4SSatish Balay         cone[1] = 19;
33559371c9d4SSatish Balay         cone[2] = 14;
33569371c9d4SSatish Balay         cone[3] = 20;
33579566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 1, cone));
33589371c9d4SSatish Balay         ornt[0] = 0;
33599371c9d4SSatish Balay         ornt[1] = 0;
33609371c9d4SSatish Balay         ornt[2] = -1;
33619371c9d4SSatish Balay         ornt[3] = 0;
33629566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 1, ornt));
33632829fed8SMatthew G. Knepley         /* Cell 2 */
33649371c9d4SSatish Balay         cone[0] = 21;
33659371c9d4SSatish Balay         cone[1] = 22;
33669371c9d4SSatish Balay         cone[2] = 18;
33679371c9d4SSatish Balay         cone[3] = 23;
33689566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 2, cone));
33699371c9d4SSatish Balay         ornt[0] = 0;
33709371c9d4SSatish Balay         ornt[1] = 0;
33719371c9d4SSatish Balay         ornt[2] = -1;
33729371c9d4SSatish Balay         ornt[3] = 0;
33739566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 2, ornt));
33742829fed8SMatthew G. Knepley         /* Cell 3 */
33759371c9d4SSatish Balay         cone[0] = 19;
33769371c9d4SSatish Balay         cone[1] = 22;
33779371c9d4SSatish Balay         cone[2] = 24;
33789371c9d4SSatish Balay         cone[3] = 15;
33799566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 3, cone));
33809371c9d4SSatish Balay         ornt[0] = -1;
33819371c9d4SSatish Balay         ornt[1] = -1;
33829371c9d4SSatish Balay         ornt[2] = 0;
33839371c9d4SSatish Balay         ornt[3] = -1;
33849566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 3, ornt));
33852829fed8SMatthew G. Knepley         /* Cell 4 */
33869371c9d4SSatish Balay         cone[0] = 16;
33879371c9d4SSatish Balay         cone[1] = 24;
33889371c9d4SSatish Balay         cone[2] = 21;
33899371c9d4SSatish Balay         cone[3] = 25;
33909566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 4, cone));
33919371c9d4SSatish Balay         ornt[0] = -1;
33929371c9d4SSatish Balay         ornt[1] = -1;
33939371c9d4SSatish Balay         ornt[2] = -1;
33949371c9d4SSatish Balay         ornt[3] = 0;
33959566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 4, ornt));
33962829fed8SMatthew G. Knepley         /* Cell 5 */
33979371c9d4SSatish Balay         cone[0] = 20;
33989371c9d4SSatish Balay         cone[1] = 17;
33999371c9d4SSatish Balay         cone[2] = 25;
34009371c9d4SSatish Balay         cone[3] = 23;
34019566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 5, cone));
34029371c9d4SSatish Balay         ornt[0] = -1;
34039371c9d4SSatish Balay         ornt[1] = -1;
34049371c9d4SSatish Balay         ornt[2] = -1;
34059371c9d4SSatish Balay         ornt[3] = -1;
34069566063dSJacob Faibussowitsch         PetscCall(DMPlexSetConeOrientation(dm, 5, ornt));
34072829fed8SMatthew G. Knepley         /* Edges */
34089371c9d4SSatish Balay         cone[0] = 6;
34099371c9d4SSatish Balay         cone[1] = 7;
34109566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 14, cone));
34119371c9d4SSatish Balay         cone[0] = 7;
34129371c9d4SSatish Balay         cone[1] = 8;
34139566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 15, cone));
34149371c9d4SSatish Balay         cone[0] = 8;
34159371c9d4SSatish Balay         cone[1] = 9;
34169566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 16, cone));
34179371c9d4SSatish Balay         cone[0] = 9;
34189371c9d4SSatish Balay         cone[1] = 6;
34199566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 17, cone));
34209371c9d4SSatish Balay         cone[0] = 10;
34219371c9d4SSatish Balay         cone[1] = 11;
34229566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 18, cone));
34239371c9d4SSatish Balay         cone[0] = 11;
34249371c9d4SSatish Balay         cone[1] = 7;
34259566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 19, cone));
34269371c9d4SSatish Balay         cone[0] = 6;
34279371c9d4SSatish Balay         cone[1] = 10;
34289566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 20, cone));
34299371c9d4SSatish Balay         cone[0] = 12;
34309371c9d4SSatish Balay         cone[1] = 13;
34319566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 21, cone));
34329371c9d4SSatish Balay         cone[0] = 13;
34339371c9d4SSatish Balay         cone[1] = 11;
34349566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 22, cone));
34359371c9d4SSatish Balay         cone[0] = 10;
34369371c9d4SSatish Balay         cone[1] = 12;
34379566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 23, cone));
34389371c9d4SSatish Balay         cone[0] = 13;
34399371c9d4SSatish Balay         cone[1] = 8;
34409566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 24, cone));
34419371c9d4SSatish Balay         cone[0] = 12;
34429371c9d4SSatish Balay         cone[1] = 9;
34439566063dSJacob Faibussowitsch         PetscCall(DMPlexSetCone(dm, 25, cone));
344445da822fSValeria Barra       }
34459566063dSJacob Faibussowitsch       PetscCall(DMPlexSymmetrize(dm));
34469566063dSJacob Faibussowitsch       PetscCall(DMPlexStratify(dm));
34472829fed8SMatthew G. Knepley       /* Build coordinates */
34489566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3449dd400576SPatrick Sanan       if (rank == 0) {
34509371c9d4SSatish Balay         coordsIn[0 * embedDim + 0] = -R;
34519371c9d4SSatish Balay         coordsIn[0 * embedDim + 1] = R;
34529371c9d4SSatish Balay         coordsIn[0 * embedDim + 2] = -R;
34539371c9d4SSatish Balay         coordsIn[1 * embedDim + 0] = R;
34549371c9d4SSatish Balay         coordsIn[1 * embedDim + 1] = R;
34559371c9d4SSatish Balay         coordsIn[1 * embedDim + 2] = -R;
34569371c9d4SSatish Balay         coordsIn[2 * embedDim + 0] = R;
34579371c9d4SSatish Balay         coordsIn[2 * embedDim + 1] = -R;
34589371c9d4SSatish Balay         coordsIn[2 * embedDim + 2] = -R;
34599371c9d4SSatish Balay         coordsIn[3 * embedDim + 0] = -R;
34609371c9d4SSatish Balay         coordsIn[3 * embedDim + 1] = -R;
34619371c9d4SSatish Balay         coordsIn[3 * embedDim + 2] = -R;
34629371c9d4SSatish Balay         coordsIn[4 * embedDim + 0] = -R;
34639371c9d4SSatish Balay         coordsIn[4 * embedDim + 1] = R;
34649371c9d4SSatish Balay         coordsIn[4 * embedDim + 2] = R;
34659371c9d4SSatish Balay         coordsIn[5 * embedDim + 0] = R;
34669371c9d4SSatish Balay         coordsIn[5 * embedDim + 1] = R;
34679371c9d4SSatish Balay         coordsIn[5 * embedDim + 2] = R;
34689371c9d4SSatish Balay         coordsIn[6 * embedDim + 0] = -R;
34699371c9d4SSatish Balay         coordsIn[6 * embedDim + 1] = -R;
34709371c9d4SSatish Balay         coordsIn[6 * embedDim + 2] = R;
34719371c9d4SSatish Balay         coordsIn[7 * embedDim + 0] = R;
34729371c9d4SSatish Balay         coordsIn[7 * embedDim + 1] = -R;
34739371c9d4SSatish Balay         coordsIn[7 * embedDim + 2] = R;
347465a81367SMatthew G. Knepley       }
347545da822fSValeria Barra     }
347665a81367SMatthew G. Knepley     break;
347765a81367SMatthew G. Knepley   case 3:
3478116ded15SMatthew G. Knepley     if (simplex) {
3479116ded15SMatthew G. Knepley       const PetscReal edgeLen         = 1.0 / PETSC_PHI;
348051a74b61SMatthew G. Knepley       PetscReal       vertexA[4]      = {0.5, 0.5, 0.5, 0.5};
348151a74b61SMatthew G. Knepley       PetscReal       vertexB[4]      = {1.0, 0.0, 0.0, 0.0};
348251a74b61SMatthew G. Knepley       PetscReal       vertexC[4]      = {0.5, 0.5 * PETSC_PHI, 0.5 / PETSC_PHI, 0.0};
3483116ded15SMatthew G. Knepley       const PetscInt  degree          = 12;
3484116ded15SMatthew G. Knepley       PetscInt        s[4]            = {1, 1, 1};
34859371c9d4SSatish Balay       PetscInt        evenPerm[12][4] = {
34869371c9d4SSatish Balay         {0, 1, 2, 3},
34879371c9d4SSatish Balay         {0, 2, 3, 1},
34889371c9d4SSatish Balay         {0, 3, 1, 2},
34899371c9d4SSatish Balay         {1, 0, 3, 2},
34909371c9d4SSatish Balay         {1, 2, 0, 3},
34919371c9d4SSatish Balay         {1, 3, 2, 0},
34929371c9d4SSatish Balay         {2, 0, 1, 3},
34939371c9d4SSatish Balay         {2, 1, 3, 0},
34949371c9d4SSatish Balay         {2, 3, 0, 1},
34959371c9d4SSatish Balay         {3, 0, 2, 1},
34969371c9d4SSatish Balay         {3, 1, 0, 2},
34979371c9d4SSatish Balay         {3, 2, 1, 0}
34989371c9d4SSatish Balay       };
3499116ded15SMatthew G. Knepley       PetscInt  cone[4];
3500116ded15SMatthew G. Knepley       PetscInt *graph, p, i, j, k, l;
3501116ded15SMatthew G. Knepley 
35029371c9d4SSatish Balay       vertexA[0] *= R;
35039371c9d4SSatish Balay       vertexA[1] *= R;
35049371c9d4SSatish Balay       vertexA[2] *= R;
35059371c9d4SSatish Balay       vertexA[3] *= R;
35069371c9d4SSatish Balay       vertexB[0] *= R;
35079371c9d4SSatish Balay       vertexB[1] *= R;
35089371c9d4SSatish Balay       vertexB[2] *= R;
35099371c9d4SSatish Balay       vertexB[3] *= R;
35109371c9d4SSatish Balay       vertexC[0] *= R;
35119371c9d4SSatish Balay       vertexC[1] *= R;
35129371c9d4SSatish Balay       vertexC[2] *= R;
35139371c9d4SSatish Balay       vertexC[3] *= R;
3514dd400576SPatrick Sanan       numCells    = rank == 0 ? 600 : 0;
3515dd400576SPatrick Sanan       numVerts    = rank == 0 ? 120 : 0;
3516116ded15SMatthew G. Knepley       firstVertex = numCells;
3517116ded15SMatthew G. Knepley       /* Use the 600-cell, which for a unit sphere has coordinates which are
3518116ded15SMatthew G. Knepley 
3519116ded15SMatthew G. Knepley            1/2 (\pm 1, \pm 1,    \pm 1, \pm 1)                          16
3520116ded15SMatthew G. Knepley                (\pm 1,    0,       0,      0)  all cyclic permutations   8
3521116ded15SMatthew G. Knepley            1/2 (\pm 1, \pm phi, \pm 1/phi, 0)  all even permutations    96
3522116ded15SMatthew G. Knepley 
3523116ded15SMatthew G. Knepley          where \phi^2 - \phi - 1 = 0, meaning \phi is the golden ratio \frac{1 + \sqrt{5}}{2}. The edge
35246333ae4fSvaleriabarra          length is then given by 1/\phi = 0.61803.
3525116ded15SMatthew G. Knepley 
3526116ded15SMatthew G. Knepley          http://buzzard.pugetsound.edu/sage-practice/ch03s03.html
3527116ded15SMatthew G. Knepley          http://mathworld.wolfram.com/600-Cell.html
3528116ded15SMatthew G. Knepley       */
3529116ded15SMatthew G. Knepley       /* Construct vertices */
35309566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numVerts * embedDim, &coordsIn));
3531116ded15SMatthew G. Knepley       i = 0;
3532dd400576SPatrick Sanan       if (rank == 0) {
3533116ded15SMatthew G. Knepley         for (s[0] = -1; s[0] < 2; s[0] += 2) {
3534116ded15SMatthew G. Knepley           for (s[1] = -1; s[1] < 2; s[1] += 2) {
3535116ded15SMatthew G. Knepley             for (s[2] = -1; s[2] < 2; s[2] += 2) {
3536116ded15SMatthew G. Knepley               for (s[3] = -1; s[3] < 2; s[3] += 2) {
3537116ded15SMatthew G. Knepley                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[d] * vertexA[d];
3538116ded15SMatthew G. Knepley                 ++i;
3539116ded15SMatthew G. Knepley               }
3540116ded15SMatthew G. Knepley             }
3541116ded15SMatthew G. Knepley           }
3542116ded15SMatthew G. Knepley         }
3543116ded15SMatthew G. Knepley         for (p = 0; p < embedDim; ++p) {
3544116ded15SMatthew G. Knepley           s[1] = s[2] = s[3] = 1;
3545116ded15SMatthew G. Knepley           for (s[0] = -1; s[0] < 2; s[0] += 2) {
3546116ded15SMatthew G. Knepley             for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[(d + p) % embedDim] * vertexB[(d + p) % embedDim];
3547116ded15SMatthew G. Knepley             ++i;
3548116ded15SMatthew G. Knepley           }
3549116ded15SMatthew G. Knepley         }
3550116ded15SMatthew G. Knepley         for (p = 0; p < 12; ++p) {
3551116ded15SMatthew G. Knepley           s[3] = 1;
3552116ded15SMatthew G. Knepley           for (s[0] = -1; s[0] < 2; s[0] += 2) {
3553116ded15SMatthew G. Knepley             for (s[1] = -1; s[1] < 2; s[1] += 2) {
3554116ded15SMatthew G. Knepley               for (s[2] = -1; s[2] < 2; s[2] += 2) {
3555116ded15SMatthew G. Knepley                 for (d = 0; d < embedDim; ++d) coordsIn[i * embedDim + d] = s[evenPerm[p][d]] * vertexC[evenPerm[p][d]];
3556116ded15SMatthew G. Knepley                 ++i;
3557116ded15SMatthew G. Knepley               }
3558116ded15SMatthew G. Knepley             }
3559116ded15SMatthew G. Knepley           }
3560116ded15SMatthew G. Knepley         }
356145da822fSValeria Barra       }
356263a3b9bcSJacob Faibussowitsch       PetscCheck(i == numVerts, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertices %" PetscInt_FMT " != %" PetscInt_FMT, i, numVerts);
3563116ded15SMatthew G. Knepley       /* Construct graph */
35649566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numVerts * numVerts, &graph));
3565116ded15SMatthew G. Knepley       for (i = 0; i < numVerts; ++i) {
3566116ded15SMatthew G. Knepley         for (j = 0, k = 0; j < numVerts; ++j) {
35679371c9d4SSatish Balay           if (PetscAbsReal(DiffNormReal(embedDim, &coordsIn[i * embedDim], &coordsIn[j * embedDim]) - edgeLen) < PETSC_SMALL) {
35689371c9d4SSatish Balay             graph[i * numVerts + j] = 1;
35699371c9d4SSatish Balay             ++k;
35709371c9d4SSatish Balay           }
3571116ded15SMatthew G. Knepley         }
357263a3b9bcSJacob Faibussowitsch         PetscCheck(k == degree, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid 600-cell, vertex %" PetscInt_FMT " degree %" PetscInt_FMT " != %" PetscInt_FMT, i, k, degree);
3573116ded15SMatthew G. Knepley       }
3574116ded15SMatthew G. Knepley       /* Build Topology */
35759566063dSJacob Faibussowitsch       PetscCall(DMPlexSetChart(dm, 0, numCells + numVerts));
357607c565c5SJose E. Roman       for (PetscInt c = 0; c < numCells; c++) PetscCall(DMPlexSetConeSize(dm, c, embedDim));
35779566063dSJacob Faibussowitsch       PetscCall(DMSetUp(dm)); /* Allocate space for cones */
3578116ded15SMatthew G. Knepley       /* Cells */
3579dd400576SPatrick Sanan       if (rank == 0) {
358007c565c5SJose E. Roman         for (PetscInt i = 0, c = 0; i < numVerts; ++i) {
3581116ded15SMatthew G. Knepley           for (j = 0; j < i; ++j) {
3582116ded15SMatthew G. Knepley             for (k = 0; k < j; ++k) {
3583116ded15SMatthew G. Knepley               for (l = 0; l < k; ++l) {
35849371c9d4SSatish Balay                 if (graph[i * numVerts + j] && graph[j * numVerts + k] && graph[k * numVerts + i] && graph[l * numVerts + i] && graph[l * numVerts + j] && graph[l * numVerts + k]) {
35859371c9d4SSatish Balay                   cone[0] = firstVertex + i;
35869371c9d4SSatish Balay                   cone[1] = firstVertex + j;
35879371c9d4SSatish Balay                   cone[2] = firstVertex + k;
35889371c9d4SSatish Balay                   cone[3] = firstVertex + l;
3589116ded15SMatthew G. Knepley                   /* Check orientation: https://ef.gy/linear-algebra:normal-vectors-in-higher-dimensional-spaces */
3590116ded15SMatthew G. Knepley                   {
35919371c9d4SSatish Balay                     const PetscInt epsilon[4][4][4][4] = {
35929371c9d4SSatish Balay                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, -1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 0, 0}, {0, 1, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 1, 0}, {0, -1, 0, 0}, {0, 0, 0, 0}}},
3593116ded15SMatthew G. Knepley 
35949371c9d4SSatish Balay                       {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, -1}, {0, 0, 1, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 0, 0, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}}, {{0, 0, -1, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}}},
3595116ded15SMatthew G. Knepley 
35969371c9d4SSatish Balay                       {{{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 0}, {0, -1, 0, 0}}, {{0, 0, 0, -1}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}},  {{0, 1, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}},
3597116ded15SMatthew G. Knepley 
35989371c9d4SSatish Balay                       {{{0, 0, 0, 0}, {0, 0, -1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 1, 0}, {0, 0, 0, 0}, {-1, 0, 0, 0}, {0, 0, 0, 0}}, {{0, -1, 0, 0}, {1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} }
35999371c9d4SSatish Balay                     };
3600116ded15SMatthew G. Knepley                     PetscReal normal[4];
3601116ded15SMatthew G. Knepley                     PetscInt  e, f, g;
3602116ded15SMatthew G. Knepley 
3603116ded15SMatthew G. Knepley                     for (d = 0; d < embedDim; ++d) {
3604116ded15SMatthew G. Knepley                       normal[d] = 0.0;
3605116ded15SMatthew G. Knepley                       for (e = 0; e < embedDim; ++e) {
3606116ded15SMatthew G. Knepley                         for (f = 0; f < embedDim; ++f) {
3607116ded15SMatthew G. Knepley                           for (g = 0; g < embedDim; ++g) {
3608116ded15SMatthew G. Knepley                             normal[d] += epsilon[d][e][f][g] * (coordsIn[j * embedDim + e] - coordsIn[i * embedDim + e]) * (coordsIn[k * embedDim + f] - coordsIn[i * embedDim + f]) * (coordsIn[l * embedDim + f] - coordsIn[i * embedDim + f]);
3609116ded15SMatthew G. Knepley                           }
3610116ded15SMatthew G. Knepley                         }
3611116ded15SMatthew G. Knepley                       }
3612116ded15SMatthew G. Knepley                     }
36139371c9d4SSatish Balay                     if (DotReal(embedDim, normal, &coordsIn[i * embedDim]) < 0) {
36149371c9d4SSatish Balay                       PetscInt tmp = cone[1];
36159371c9d4SSatish Balay                       cone[1]      = cone[2];
36169371c9d4SSatish Balay                       cone[2]      = tmp;
36179371c9d4SSatish Balay                     }
3618116ded15SMatthew G. Knepley                   }
36199566063dSJacob Faibussowitsch                   PetscCall(DMPlexSetCone(dm, c++, cone));
3620116ded15SMatthew G. Knepley                 }
3621116ded15SMatthew G. Knepley               }
3622116ded15SMatthew G. Knepley             }
3623116ded15SMatthew G. Knepley           }
3624116ded15SMatthew G. Knepley         }
362545da822fSValeria Barra       }
36269566063dSJacob Faibussowitsch       PetscCall(DMPlexSymmetrize(dm));
36279566063dSJacob Faibussowitsch       PetscCall(DMPlexStratify(dm));
36289566063dSJacob Faibussowitsch       PetscCall(PetscFree(graph));
3629116ded15SMatthew G. Knepley     }
3630f4d061e9SPierre Jolivet     break;
3631d71ae5a4SJacob Faibussowitsch   default:
3632d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension for sphere: %" PetscInt_FMT, dim);
363365a81367SMatthew G. Knepley   }
363465a81367SMatthew G. Knepley   /* Create coordinates */
36359566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
36369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
36379566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, embedDim));
36389566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numVerts));
36392829fed8SMatthew G. Knepley   for (v = firstVertex; v < firstVertex + numVerts; ++v) {
36409566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, embedDim));
36419566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, embedDim));
36422829fed8SMatthew G. Knepley   }
36439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
36449566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
36459566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
36469566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, embedDim));
36479566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
36489566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
36499566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
36509566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
36519371c9d4SSatish Balay   for (v = 0; v < numVerts; ++v)
3652ad540459SPierre Jolivet     for (d = 0; d < embedDim; ++d) coords[v * embedDim + d] = coordsIn[v * embedDim + d];
36539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
36549566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
36559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
36569566063dSJacob Faibussowitsch   PetscCall(PetscFree(coordsIn));
365751a74b61SMatthew G. Knepley   {
365851a74b61SMatthew G. Knepley     DM          cdm;
365951a74b61SMatthew G. Knepley     PetscDS     cds;
36609318fe57SMatthew G. Knepley     PetscScalar c = R;
366151a74b61SMatthew G. Knepley 
3662509b31aaSMatthew G. Knepley     PetscCall(DMPlexSetCoordinateMap(dm, snapToSphere));
3663e65c294aSksagiyam     PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
36649566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(dm, &cdm));
36659566063dSJacob Faibussowitsch     PetscCall(DMGetDS(cdm, &cds));
36669566063dSJacob Faibussowitsch     PetscCall(PetscDSSetConstants(cds, 1, &c));
366751a74b61SMatthew G. Knepley   }
366846139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
36699318fe57SMatthew G. Knepley   /* Wait for coordinate creation before doing in-place modification */
36709566063dSJacob Faibussowitsch   if (simplex) PetscCall(DMPlexInterpolateInPlace_Internal(dm));
36713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36729318fe57SMatthew G. Knepley }
36739318fe57SMatthew G. Knepley 
3674b7f5c055SJed Brown typedef void (*TPSEvaluateFunc)(const PetscReal[], PetscReal *, PetscReal[], PetscReal (*)[3]);
3675b7f5c055SJed Brown 
3676b7f5c055SJed Brown /*
3677b7f5c055SJed Brown  The Schwarz P implicit surface is
3678b7f5c055SJed Brown 
3679b7f5c055SJed Brown      f(x) = cos(x0) + cos(x1) + cos(x2) = 0
3680b7f5c055SJed Brown */
3681d71ae5a4SJacob Faibussowitsch static void TPSEvaluate_SchwarzP(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
3682d71ae5a4SJacob Faibussowitsch {
3683b7f5c055SJed Brown   PetscReal c[3] = {PetscCosReal(y[0] * PETSC_PI), PetscCosReal(y[1] * PETSC_PI), PetscCosReal(y[2] * PETSC_PI)};
3684b7f5c055SJed Brown   PetscReal g[3] = {-PetscSinReal(y[0] * PETSC_PI), -PetscSinReal(y[1] * PETSC_PI), -PetscSinReal(y[2] * PETSC_PI)};
3685b7f5c055SJed Brown   f[0]           = c[0] + c[1] + c[2];
3686b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) {
3687b7f5c055SJed Brown     grad[i] = PETSC_PI * g[i];
3688ad540459SPierre Jolivet     for (PetscInt j = 0; j < 3; j++) hess[i][j] = (i == j) ? -PetscSqr(PETSC_PI) * c[i] : 0.;
3689b7f5c055SJed Brown   }
3690b7f5c055SJed Brown }
3691b7f5c055SJed Brown 
36924663dae6SJed Brown // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
3693d71ae5a4SJacob Faibussowitsch static PetscErrorCode TPSExtrudeNormalFunc_SchwarzP(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
3694d71ae5a4SJacob Faibussowitsch {
3695ad540459SPierre Jolivet   for (PetscInt i = 0; i < 3; i++) u[i] = -PETSC_PI * PetscSinReal(x[i] * PETSC_PI);
36963ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
36974663dae6SJed Brown }
36984663dae6SJed Brown 
3699b7f5c055SJed Brown /*
3700b7f5c055SJed Brown  The Gyroid implicit surface is
3701b7f5c055SJed Brown 
3702b7f5c055SJed Brown  f(x,y,z) = sin(pi * x) * cos (pi * (y + 1/2))  + sin(pi * (y + 1/2)) * cos(pi * (z + 1/4)) + sin(pi * (z + 1/4)) * cos(pi * x)
3703b7f5c055SJed Brown 
3704b7f5c055SJed Brown */
3705d71ae5a4SJacob Faibussowitsch static void TPSEvaluate_Gyroid(const PetscReal y[3], PetscReal *f, PetscReal grad[], PetscReal (*hess)[3])
3706d71ae5a4SJacob Faibussowitsch {
3707b7f5c055SJed Brown   PetscReal s[3] = {PetscSinReal(PETSC_PI * y[0]), PetscSinReal(PETSC_PI * (y[1] + .5)), PetscSinReal(PETSC_PI * (y[2] + .25))};
3708b7f5c055SJed Brown   PetscReal c[3] = {PetscCosReal(PETSC_PI * y[0]), PetscCosReal(PETSC_PI * (y[1] + .5)), PetscCosReal(PETSC_PI * (y[2] + .25))};
3709b7f5c055SJed Brown   f[0]           = s[0] * c[1] + s[1] * c[2] + s[2] * c[0];
3710b7f5c055SJed Brown   grad[0]        = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
3711b7f5c055SJed Brown   grad[1]        = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
3712b7f5c055SJed Brown   grad[2]        = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
3713b7f5c055SJed Brown   hess[0][0]     = -PetscSqr(PETSC_PI) * (s[0] * c[1] + s[2] * c[0]);
3714b7f5c055SJed Brown   hess[0][1]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
3715b7f5c055SJed Brown   hess[0][2]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
3716b7f5c055SJed Brown   hess[1][0]     = -PetscSqr(PETSC_PI) * (s[1] * c[2] + s[0] * c[1]);
3717b7f5c055SJed Brown   hess[1][1]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
3718b7f5c055SJed Brown   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[0] * s[1]);
3719b7f5c055SJed Brown   hess[2][0]     = -PetscSqr(PETSC_PI) * (s[2] * c[0] + s[1] * c[2]);
3720b7f5c055SJed Brown   hess[2][1]     = -PetscSqr(PETSC_PI) * (c[2] * s[0]);
3721b7f5c055SJed Brown   hess[2][2]     = -PetscSqr(PETSC_PI) * (c[1] * s[2]);
3722b7f5c055SJed Brown }
3723b7f5c055SJed Brown 
37244663dae6SJed Brown // u[] is a tentative normal on input. Replace with the implicit function gradient in the same direction
3725d71ae5a4SJacob Faibussowitsch static PetscErrorCode TPSExtrudeNormalFunc_Gyroid(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt r, PetscScalar u[], void *ctx)
3726d71ae5a4SJacob Faibussowitsch {
37274663dae6SJed Brown   PetscReal s[3] = {PetscSinReal(PETSC_PI * x[0]), PetscSinReal(PETSC_PI * (x[1] + .5)), PetscSinReal(PETSC_PI * (x[2] + .25))};
37284663dae6SJed Brown   PetscReal c[3] = {PetscCosReal(PETSC_PI * x[0]), PetscCosReal(PETSC_PI * (x[1] + .5)), PetscCosReal(PETSC_PI * (x[2] + .25))};
37294663dae6SJed Brown   u[0]           = PETSC_PI * (c[0] * c[1] - s[2] * s[0]);
37304663dae6SJed Brown   u[1]           = PETSC_PI * (c[1] * c[2] - s[0] * s[1]);
37314663dae6SJed Brown   u[2]           = PETSC_PI * (c[2] * c[0] - s[1] * s[2]);
37323ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
37334663dae6SJed Brown }
37344663dae6SJed Brown 
3735b7f5c055SJed Brown /*
3736b7f5c055SJed Brown    We wish to solve
3737b7f5c055SJed Brown 
3738b7f5c055SJed Brown          min_y || y - x ||^2  subject to f(y) = 0
3739b7f5c055SJed Brown 
3740b7f5c055SJed Brown    Let g(y) = grad(f).  The minimization problem is equivalent to asking to satisfy
3741b7f5c055SJed Brown    f(y) = 0 and (y-x) is parallel to g(y).  We do this by using Householder QR to obtain a basis for the
3742b7f5c055SJed Brown    tangent space and ask for both components in the tangent space to be zero.
3743b7f5c055SJed Brown 
3744b7f5c055SJed Brown    Take g to be a column vector and compute the "full QR" factorization Q R = g,
3745b7f5c055SJed Brown    where Q = I - 2 n n^T is a symmetric orthogonal matrix.
3746b7f5c055SJed Brown    The first column of Q is parallel to g so the remaining two columns span the null space.
3747b7f5c055SJed Brown    Let Qn = Q[:,1:] be those remaining columns.  Then Qn Qn^T is an orthogonal projector into the tangent space.
3748da81f932SPierre Jolivet    Since Q is symmetric, this is equivalent to multiplying by Q and taking the last two entries.
3749b7f5c055SJed Brown    In total, we have a system of 3 equations in 3 unknowns:
3750b7f5c055SJed Brown 
3751b7f5c055SJed Brown      f(y) = 0                       1 equation
3752b7f5c055SJed Brown      Qn^T (y - x) = 0               2 equations
3753b7f5c055SJed Brown 
3754b7f5c055SJed Brown    Here, we compute the residual and Jacobian of this system.
3755b7f5c055SJed Brown */
3756d71ae5a4SJacob Faibussowitsch static void TPSNearestPointResJac(TPSEvaluateFunc feval, const PetscScalar x[], const PetscScalar y[], PetscScalar res[], PetscScalar J[])
3757d71ae5a4SJacob Faibussowitsch {
3758b7f5c055SJed Brown   PetscReal yreal[3] = {PetscRealPart(y[0]), PetscRealPart(y[1]), PetscRealPart(y[2])};
3759b7f5c055SJed Brown   PetscReal d[3]     = {PetscRealPart(y[0] - x[0]), PetscRealPart(y[1] - x[1]), PetscRealPart(y[2] - x[2])};
37602f0490c0SSatish Balay   PetscReal f, grad[3], n[3], norm, norm_y[3], nd, nd_y[3], sign;
37619371c9d4SSatish Balay   PetscReal n_y[3][3] = {
37629371c9d4SSatish Balay     {0, 0, 0},
37639371c9d4SSatish Balay     {0, 0, 0},
37649371c9d4SSatish Balay     {0, 0, 0}
37659371c9d4SSatish Balay   };
3766b7f5c055SJed Brown 
3767b7f5c055SJed Brown   feval(yreal, &f, grad, n_y);
3768b7f5c055SJed Brown 
3769b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) n[i] = grad[i];
3770b7f5c055SJed Brown   norm = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
3771ad540459SPierre Jolivet   for (PetscInt i = 0; i < 3; i++) norm_y[i] = 1. / norm * n[i] * n_y[i][i];
3772b7f5c055SJed Brown 
3773b7f5c055SJed Brown   // Define the Householder reflector
3774b7f5c055SJed Brown   sign = n[0] >= 0 ? 1. : -1.;
3775b7f5c055SJed Brown   n[0] += norm * sign;
3776b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) n_y[0][i] += norm_y[i] * sign;
3777b7f5c055SJed Brown 
3778b7f5c055SJed Brown   norm      = PetscSqrtReal(PetscSqr(n[0]) + PetscSqr(n[1]) + PetscSqr(n[2]));
3779b7f5c055SJed Brown   norm_y[0] = 1. / norm * (n[0] * n_y[0][0]);
3780b7f5c055SJed Brown   norm_y[1] = 1. / norm * (n[0] * n_y[0][1] + n[1] * n_y[1][1]);
3781b7f5c055SJed Brown   norm_y[2] = 1. / norm * (n[0] * n_y[0][2] + n[2] * n_y[2][2]);
3782b7f5c055SJed Brown 
3783b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) {
3784b7f5c055SJed Brown     n[i] /= norm;
3785b7f5c055SJed Brown     for (PetscInt j = 0; j < 3; j++) {
3786b7f5c055SJed Brown       // note that n[i] is n_old[i]/norm when executing the code below
3787b7f5c055SJed Brown       n_y[i][j] = n_y[i][j] / norm - n[i] / norm * norm_y[j];
3788b7f5c055SJed Brown     }
3789b7f5c055SJed Brown   }
3790b7f5c055SJed Brown 
3791b7f5c055SJed Brown   nd = n[0] * d[0] + n[1] * d[1] + n[2] * d[2];
3792b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) nd_y[i] = n[i] + n_y[0][i] * d[0] + n_y[1][i] * d[1] + n_y[2][i] * d[2];
3793b7f5c055SJed Brown 
3794b7f5c055SJed Brown   res[0] = f;
3795b7f5c055SJed Brown   res[1] = d[1] - 2 * n[1] * nd;
3796b7f5c055SJed Brown   res[2] = d[2] - 2 * n[2] * nd;
3797b7f5c055SJed Brown   // J[j][i] is J_{ij} (column major)
3798b7f5c055SJed Brown   for (PetscInt j = 0; j < 3; j++) {
3799b7f5c055SJed Brown     J[0 + j * 3] = grad[j];
3800b7f5c055SJed Brown     J[1 + j * 3] = (j == 1) * 1. - 2 * (n_y[1][j] * nd + n[1] * nd_y[j]);
3801b7f5c055SJed Brown     J[2 + j * 3] = (j == 2) * 1. - 2 * (n_y[2][j] * nd + n[2] * nd_y[j]);
3802b7f5c055SJed Brown   }
3803b7f5c055SJed Brown }
3804b7f5c055SJed Brown 
3805b7f5c055SJed Brown /*
3806b7f5c055SJed Brown    Project x to the nearest point on the implicit surface using Newton's method.
3807b7f5c055SJed Brown */
3808d71ae5a4SJacob Faibussowitsch static PetscErrorCode TPSNearestPoint(TPSEvaluateFunc feval, PetscScalar x[])
3809d71ae5a4SJacob Faibussowitsch {
3810b7f5c055SJed Brown   PetscScalar y[3] = {x[0], x[1], x[2]}; // Initial guess
3811b7f5c055SJed Brown 
3812b7f5c055SJed Brown   PetscFunctionBegin;
3813b7f5c055SJed Brown   for (PetscInt iter = 0; iter < 10; iter++) {
3814b7f5c055SJed Brown     PetscScalar res[3], J[9];
3815b7f5c055SJed Brown     PetscReal   resnorm;
3816b7f5c055SJed Brown     TPSNearestPointResJac(feval, x, y, res, J);
3817b7f5c055SJed Brown     resnorm = PetscSqrtReal(PetscSqr(PetscRealPart(res[0])) + PetscSqr(PetscRealPart(res[1])) + PetscSqr(PetscRealPart(res[2])));
3818b7f5c055SJed Brown     if (0) { // Turn on this monitor if you need to confirm quadratic convergence
381963a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%" PetscInt_FMT "] res [%g %g %g]\n", iter, (double)PetscRealPart(res[0]), (double)PetscRealPart(res[1]), (double)PetscRealPart(res[2])));
3820b7f5c055SJed Brown     }
3821b7f5c055SJed Brown     if (resnorm < PETSC_SMALL) break;
3822b7f5c055SJed Brown 
3823b7f5c055SJed Brown     // Take the Newton step
38249566063dSJacob Faibussowitsch     PetscCall(PetscKernel_A_gets_inverse_A_3(J, 0., PETSC_FALSE, NULL));
3825b7f5c055SJed Brown     PetscKernel_v_gets_v_minus_A_times_w_3(y, J, res);
3826b7f5c055SJed Brown   }
3827b7f5c055SJed Brown   for (PetscInt i = 0; i < 3; i++) x[i] = y[i];
38283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3829b7f5c055SJed Brown }
3830b7f5c055SJed Brown 
3831b7f5c055SJed Brown const char *const DMPlexTPSTypes[] = {"SCHWARZ_P", "GYROID", "DMPlexTPSType", "DMPLEX_TPS_", NULL};
3832b7f5c055SJed Brown 
3833d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateTPSMesh_Internal(DM dm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness)
3834d71ae5a4SJacob Faibussowitsch {
3835b7f5c055SJed Brown   PetscMPIInt rank;
3836b7f5c055SJed Brown   PetscInt    topoDim = 2, spaceDim = 3, numFaces = 0, numVertices = 0, numEdges = 0;
3837b7f5c055SJed Brown   PetscInt (*edges)[2] = NULL, *edgeSets = NULL;
3838b7f5c055SJed Brown   PetscInt           *cells_flat = NULL;
3839b7f5c055SJed Brown   PetscReal          *vtxCoords  = NULL;
3840b7f5c055SJed Brown   TPSEvaluateFunc     evalFunc   = NULL;
38418434afd1SBarry Smith   PetscSimplePointFn *normalFunc = NULL;
3842b7f5c055SJed Brown   DMLabel             label;
3843b7f5c055SJed Brown 
3844b7f5c055SJed Brown   PetscFunctionBegin;
384546139095SJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_Generate, dm, 0, 0, 0));
38469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
384763a3b9bcSJacob Faibussowitsch   PetscCheck((layers != 0) ^ (thickness == 0.), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Layers %" PetscInt_FMT " must be nonzero iff thickness %g is nonzero", layers, (double)thickness);
3848b7f5c055SJed Brown   switch (tpstype) {
3849b7f5c055SJed Brown   case DMPLEX_TPS_SCHWARZ_P:
3850b7f5c055SJed Brown     PetscCheck(!periodic || (periodic[0] == DM_BOUNDARY_NONE && periodic[1] == DM_BOUNDARY_NONE && periodic[2] == DM_BOUNDARY_NONE), PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Schwarz P does not support periodic meshes");
3851c5853193SPierre Jolivet     if (rank == 0) {
3852b7f5c055SJed Brown       PetscInt (*cells)[6][4][4] = NULL; // [junction, junction-face, cell, conn]
3853b7f5c055SJed Brown       PetscInt  Njunctions = 0, Ncuts = 0, Npipes[3], vcount;
3854b7f5c055SJed Brown       PetscReal L = 1;
3855b7f5c055SJed Brown 
3856b7f5c055SJed Brown       Npipes[0]   = (extent[0] + 1) * extent[1] * extent[2];
3857b7f5c055SJed Brown       Npipes[1]   = extent[0] * (extent[1] + 1) * extent[2];
3858b7f5c055SJed Brown       Npipes[2]   = extent[0] * extent[1] * (extent[2] + 1);
3859b7f5c055SJed Brown       Njunctions  = extent[0] * extent[1] * extent[2];
3860b7f5c055SJed Brown       Ncuts       = 2 * (extent[0] * extent[1] + extent[1] * extent[2] + extent[2] * extent[0]);
3861b7f5c055SJed Brown       numVertices = 4 * (Npipes[0] + Npipes[1] + Npipes[2]) + 8 * Njunctions;
38629566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(3 * numVertices, &vtxCoords));
38639566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Njunctions, &cells));
38649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Ncuts * 4, &edges));
38659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(Ncuts * 4, &edgeSets));
3866b7f5c055SJed Brown       // x-normal pipes
3867b7f5c055SJed Brown       vcount = 0;
3868b7f5c055SJed Brown       for (PetscInt i = 0; i < extent[0] + 1; i++) {
3869b7f5c055SJed Brown         for (PetscInt j = 0; j < extent[1]; j++) {
3870b7f5c055SJed Brown           for (PetscInt k = 0; k < extent[2]; k++) {
3871b7f5c055SJed Brown             for (PetscInt l = 0; l < 4; l++) {
3872b7f5c055SJed Brown               vtxCoords[vcount++] = (2 * i - 1) * L;
3873b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * j * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3874b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * k * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3875b7f5c055SJed Brown             }
3876b7f5c055SJed Brown           }
3877b7f5c055SJed Brown         }
3878b7f5c055SJed Brown       }
3879b7f5c055SJed Brown       // y-normal pipes
3880b7f5c055SJed Brown       for (PetscInt i = 0; i < extent[0]; i++) {
3881b7f5c055SJed Brown         for (PetscInt j = 0; j < extent[1] + 1; j++) {
3882b7f5c055SJed Brown           for (PetscInt k = 0; k < extent[2]; k++) {
3883b7f5c055SJed Brown             for (PetscInt l = 0; l < 4; l++) {
3884b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * i * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3885b7f5c055SJed Brown               vtxCoords[vcount++] = (2 * j - 1) * L;
3886b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * k * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3887b7f5c055SJed Brown             }
3888b7f5c055SJed Brown           }
3889b7f5c055SJed Brown         }
3890b7f5c055SJed Brown       }
3891b7f5c055SJed Brown       // z-normal pipes
3892b7f5c055SJed Brown       for (PetscInt i = 0; i < extent[0]; i++) {
3893b7f5c055SJed Brown         for (PetscInt j = 0; j < extent[1]; j++) {
3894b7f5c055SJed Brown           for (PetscInt k = 0; k < extent[2] + 1; k++) {
3895b7f5c055SJed Brown             for (PetscInt l = 0; l < 4; l++) {
3896b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * i * L + PetscCosReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3897b7f5c055SJed Brown               vtxCoords[vcount++] = 2 * j * L + PetscSinReal((2 * l + 1) * PETSC_PI / 4) * L / 2;
3898b7f5c055SJed Brown               vtxCoords[vcount++] = (2 * k - 1) * L;
3899b7f5c055SJed Brown             }
3900b7f5c055SJed Brown           }
3901b7f5c055SJed Brown         }
3902b7f5c055SJed Brown       }
3903b7f5c055SJed Brown       // junctions
3904b7f5c055SJed Brown       for (PetscInt i = 0; i < extent[0]; i++) {
3905b7f5c055SJed Brown         for (PetscInt j = 0; j < extent[1]; j++) {
3906b7f5c055SJed Brown           for (PetscInt k = 0; k < extent[2]; k++) {
3907b7f5c055SJed Brown             const PetscInt J = (i * extent[1] + j) * extent[2] + k, Jvoff = (Npipes[0] + Npipes[1] + Npipes[2]) * 4 + J * 8;
3908b7f5c055SJed Brown             PetscCheck(vcount / 3 == Jvoff, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected vertex count");
3909b7f5c055SJed Brown             for (PetscInt ii = 0; ii < 2; ii++) {
3910b7f5c055SJed Brown               for (PetscInt jj = 0; jj < 2; jj++) {
3911b7f5c055SJed Brown                 for (PetscInt kk = 0; kk < 2; kk++) {
3912b7f5c055SJed Brown                   double Ls           = (1 - sqrt(2) / 4) * L;
3913b7f5c055SJed Brown                   vtxCoords[vcount++] = 2 * i * L + (2 * ii - 1) * Ls;
3914b7f5c055SJed Brown                   vtxCoords[vcount++] = 2 * j * L + (2 * jj - 1) * Ls;
3915b7f5c055SJed Brown                   vtxCoords[vcount++] = 2 * k * L + (2 * kk - 1) * Ls;
3916b7f5c055SJed Brown                 }
3917b7f5c055SJed Brown               }
3918b7f5c055SJed Brown             }
3919b7f5c055SJed Brown             const PetscInt jfaces[3][2][4] = {
3920b7f5c055SJed Brown               {{3, 1, 0, 2}, {7, 5, 4, 6}}, // x-aligned
3921b7f5c055SJed Brown               {{5, 4, 0, 1}, {7, 6, 2, 3}}, // y-aligned
3922b7f5c055SJed Brown               {{6, 2, 0, 4}, {7, 3, 1, 5}}  // z-aligned
3923b7f5c055SJed Brown             };
3924b7f5c055SJed Brown             const PetscInt pipe_lo[3] = {// vertex numbers of pipes
39259371c9d4SSatish Balay                                          ((i * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + Npipes[0] + Npipes[1]) * 4};
3926b7f5c055SJed Brown             const PetscInt pipe_hi[3] = {// vertex numbers of pipes
39279371c9d4SSatish Balay                                          (((i + 1) * extent[1] + j) * extent[2] + k) * 4, ((i * (extent[1] + 1) + j + 1) * extent[2] + k + Npipes[0]) * 4, ((i * extent[1] + j) * (extent[2] + 1) + k + 1 + Npipes[0] + Npipes[1]) * 4};
3928b7f5c055SJed Brown             for (PetscInt dir = 0; dir < 3; dir++) { // x,y,z
3929b7f5c055SJed Brown               const PetscInt ijk[3] = {i, j, k};
3930b7f5c055SJed Brown               for (PetscInt l = 0; l < 4; l++) { // rotations
3931b7f5c055SJed Brown                 cells[J][dir * 2 + 0][l][0] = pipe_lo[dir] + l;
3932b7f5c055SJed Brown                 cells[J][dir * 2 + 0][l][1] = Jvoff + jfaces[dir][0][l];
3933b7f5c055SJed Brown                 cells[J][dir * 2 + 0][l][2] = Jvoff + jfaces[dir][0][(l - 1 + 4) % 4];
3934b7f5c055SJed Brown                 cells[J][dir * 2 + 0][l][3] = pipe_lo[dir] + (l - 1 + 4) % 4;
3935b7f5c055SJed Brown                 cells[J][dir * 2 + 1][l][0] = Jvoff + jfaces[dir][1][l];
3936b7f5c055SJed Brown                 cells[J][dir * 2 + 1][l][1] = pipe_hi[dir] + l;
3937b7f5c055SJed Brown                 cells[J][dir * 2 + 1][l][2] = pipe_hi[dir] + (l - 1 + 4) % 4;
3938b7f5c055SJed Brown                 cells[J][dir * 2 + 1][l][3] = Jvoff + jfaces[dir][1][(l - 1 + 4) % 4];
3939b7f5c055SJed Brown                 if (ijk[dir] == 0) {
3940b7f5c055SJed Brown                   edges[numEdges][0] = pipe_lo[dir] + l;
3941b7f5c055SJed Brown                   edges[numEdges][1] = pipe_lo[dir] + (l + 1) % 4;
3942b7f5c055SJed Brown                   edgeSets[numEdges] = dir * 2 + 1;
3943b7f5c055SJed Brown                   numEdges++;
3944b7f5c055SJed Brown                 }
3945b7f5c055SJed Brown                 if (ijk[dir] + 1 == extent[dir]) {
3946b7f5c055SJed Brown                   edges[numEdges][0] = pipe_hi[dir] + l;
3947b7f5c055SJed Brown                   edges[numEdges][1] = pipe_hi[dir] + (l + 1) % 4;
3948b7f5c055SJed Brown                   edgeSets[numEdges] = dir * 2 + 2;
3949b7f5c055SJed Brown                   numEdges++;
3950b7f5c055SJed Brown                 }
3951b7f5c055SJed Brown               }
3952b7f5c055SJed Brown             }
3953b7f5c055SJed Brown           }
3954b7f5c055SJed Brown         }
3955b7f5c055SJed Brown       }
395663a3b9bcSJacob Faibussowitsch       PetscCheck(numEdges == Ncuts * 4, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge count %" PetscInt_FMT " incompatible with number of cuts %" PetscInt_FMT, numEdges, Ncuts);
3957b7f5c055SJed Brown       numFaces   = 24 * Njunctions;
3958b7f5c055SJed Brown       cells_flat = cells[0][0][0];
3959b7f5c055SJed Brown     }
3960b7f5c055SJed Brown     evalFunc   = TPSEvaluate_SchwarzP;
39614663dae6SJed Brown     normalFunc = TPSExtrudeNormalFunc_SchwarzP;
3962b7f5c055SJed Brown     break;
3963b7f5c055SJed Brown   case DMPLEX_TPS_GYROID:
3964c5853193SPierre Jolivet     if (rank == 0) {
3965b7f5c055SJed Brown       // This is a coarse mesh approximation of the gyroid shifted to being the zero of the level set
3966b7f5c055SJed Brown       //
3967b7f5c055SJed Brown       //     sin(pi*x)*cos(pi*(y+1/2)) + sin(pi*(y+1/2))*cos(pi*(z+1/4)) + sin(pi*(z+1/4))*cos(x)
3968b7f5c055SJed Brown       //
3969b7f5c055SJed Brown       // on the cell [0,2]^3.
3970b7f5c055SJed Brown       //
3971b7f5c055SJed Brown       // Think about dividing that cell into four columns, and focus on the column [0,1]x[0,1]x[0,2].
3972b7f5c055SJed Brown       // If you looked at the gyroid in that column at different slices of z you would see that it kind of spins
3973b7f5c055SJed Brown       // like a boomerang:
3974b7f5c055SJed Brown       //
3975b7f5c055SJed Brown       //     z = 0          z = 1/4        z = 1/2        z = 3/4     //
3976b7f5c055SJed Brown       //     -----          -------        -------        -------     //
3977b7f5c055SJed Brown       //                                                              //
3978b7f5c055SJed Brown       //     +       +      +       +      +       +      +   \   +   //
3979b7f5c055SJed Brown       //      \                                   /            \      //
3980b7f5c055SJed Brown       //       \            `-_   _-'            /              }     //
3981b7f5c055SJed Brown       //        *-_            `-'            _-'              /      //
3982b7f5c055SJed Brown       //     +     `-+      +       +      +-'     +      +   /   +   //
3983b7f5c055SJed Brown       //                                                              //
3984b7f5c055SJed Brown       //                                                              //
3985b7f5c055SJed Brown       //     z = 1          z = 5/4        z = 3/2        z = 7/4     //
3986b7f5c055SJed Brown       //     -----          -------        -------        -------     //
3987b7f5c055SJed Brown       //                                                              //
3988b7f5c055SJed Brown       //     +-_     +      +       +      +     _-+      +   /   +   //
3989b7f5c055SJed Brown       //        `-_            _-_            _-`            /        //
3990b7f5c055SJed Brown       //           \        _-'   `-_        /              {         //
3991b7f5c055SJed Brown       //            \                       /                \        //
3992b7f5c055SJed Brown       //     +       +      +       +      +       +      +   \   +   //
3993b7f5c055SJed Brown       //
3994b7f5c055SJed Brown       //
3995b7f5c055SJed Brown       // This course mesh approximates each of these slices by two line segments,
3996b7f5c055SJed Brown       // and then connects the segments in consecutive layers with quadrilateral faces.
3997b7f5c055SJed Brown       // All of the end points of the segments are multiples of 1/4 except for the
3998b7f5c055SJed Brown       // point * in the picture for z = 0 above and the similar points in other layers.
3999b7f5c055SJed Brown       // That point is at (gamma, gamma, 0), where gamma is calculated below.
4000b7f5c055SJed Brown       //
4001b7f5c055SJed Brown       // The column  [1,2]x[1,2]x[0,2] looks the same as this column;
4002b7f5c055SJed Brown       // The columns [1,2]x[0,1]x[0,2] and [0,1]x[1,2]x[0,2] are mirror images.
4003b7f5c055SJed Brown       //
4004b7f5c055SJed Brown       // As for how this method turned into the names given to the vertices:
4005b7f5c055SJed Brown       // that was not systematic, it was just the way it worked out in my handwritten notes.
4006b7f5c055SJed Brown 
4007b7f5c055SJed Brown       PetscInt facesPerBlock = 64;
4008b7f5c055SJed Brown       PetscInt vertsPerBlock = 56;
4009b7f5c055SJed Brown       PetscInt extentPlus[3];
4010b7f5c055SJed Brown       PetscInt numBlocks, numBlocksPlus;
40119371c9d4SSatish Balay       const PetscInt A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, II = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15, Q = 16, R = 17, S = 18, T = 19, U = 20, V = 21, W = 22, X = 23, Y = 24, Z = 25, Ap = 26, Bp = 27, Cp = 28, Dp = 29, Ep = 30, Fp = 31, Gp = 32, Hp = 33, Ip = 34, Jp = 35, Kp = 36, Lp = 37, Mp = 38, Np = 39, Op = 40, Pp = 41, Qp = 42, Rp = 43, Sp = 44, Tp = 45, Up = 46, Vp = 47, Wp = 48, Xp = 49, Yp = 50, Zp = 51, Aq = 52, Bq = 53, Cq = 54, Dq = 55;
40129371c9d4SSatish Balay       const PetscInt pattern[64][4] = {
40139371c9d4SSatish Balay         /* face to vertex within the coarse discretization of a single gyroid block */
4014b7f5c055SJed Brown         /* layer 0 */
40159371c9d4SSatish Balay         {A,           C,           K,           G          },
40169371c9d4SSatish Balay         {C,           B,           II,          K          },
40179371c9d4SSatish Balay         {D,           A,           H,           L          },
40189371c9d4SSatish Balay         {B + 56 * 1,  D,           L,           J          },
40199371c9d4SSatish Balay         {E,           B + 56 * 1,  J,           N          },
40209371c9d4SSatish Balay         {A + 56 * 2,  E,           N,           H + 56 * 2 },
40219371c9d4SSatish Balay         {F,           A + 56 * 2,  G + 56 * 2,  M          },
40229371c9d4SSatish Balay         {B,           F,           M,           II         },
4023b7f5c055SJed Brown         /* layer 1 */
40249371c9d4SSatish Balay         {G,           K,           Q,           O          },
40259371c9d4SSatish Balay         {K,           II,          P,           Q          },
40269371c9d4SSatish Balay         {L,           H,           O + 56 * 1,  R          },
40279371c9d4SSatish Balay         {J,           L,           R,           P          },
40289371c9d4SSatish Balay         {N,           J,           P,           S          },
40299371c9d4SSatish Balay         {H + 56 * 2,  N,           S,           O + 56 * 3 },
40309371c9d4SSatish Balay         {M,           G + 56 * 2,  O + 56 * 2,  T          },
40319371c9d4SSatish Balay         {II,          M,           T,           P          },
4032b7f5c055SJed Brown         /* layer 2 */
40339371c9d4SSatish Balay         {O,           Q,           Y,           U          },
40349371c9d4SSatish Balay         {Q,           P,           W,           Y          },
40359371c9d4SSatish Balay         {R,           O + 56 * 1,  U + 56 * 1,  Ap         },
40369371c9d4SSatish Balay         {P,           R,           Ap,          W          },
40379371c9d4SSatish Balay         {S,           P,           X,           Bp         },
40389371c9d4SSatish Balay         {O + 56 * 3,  S,           Bp,          V + 56 * 1 },
40399371c9d4SSatish Balay         {T,           O + 56 * 2,  V,           Z          },
40409371c9d4SSatish Balay         {P,           T,           Z,           X          },
4041b7f5c055SJed Brown         /* layer 3 */
40429371c9d4SSatish Balay         {U,           Y,           Ep,          Dp         },
40439371c9d4SSatish Balay         {Y,           W,           Cp,          Ep         },
40449371c9d4SSatish Balay         {Ap,          U + 56 * 1,  Dp + 56 * 1, Gp         },
40459371c9d4SSatish Balay         {W,           Ap,          Gp,          Cp         },
40469371c9d4SSatish Balay         {Bp,          X,           Cp + 56 * 2, Fp         },
40479371c9d4SSatish Balay         {V + 56 * 1,  Bp,          Fp,          Dp + 56 * 1},
40489371c9d4SSatish Balay         {Z,           V,           Dp,          Hp         },
40499371c9d4SSatish Balay         {X,           Z,           Hp,          Cp + 56 * 2},
4050b7f5c055SJed Brown         /* layer 4 */
40519371c9d4SSatish Balay         {Dp,          Ep,          Mp,          Kp         },
40529371c9d4SSatish Balay         {Ep,          Cp,          Ip,          Mp         },
40539371c9d4SSatish Balay         {Gp,          Dp + 56 * 1, Lp,          Np         },
40549371c9d4SSatish Balay         {Cp,          Gp,          Np,          Jp         },
40559371c9d4SSatish Balay         {Fp,          Cp + 56 * 2, Jp + 56 * 2, Pp         },
40569371c9d4SSatish Balay         {Dp + 56 * 1, Fp,          Pp,          Lp         },
40579371c9d4SSatish Balay         {Hp,          Dp,          Kp,          Op         },
40589371c9d4SSatish Balay         {Cp + 56 * 2, Hp,          Op,          Ip + 56 * 2},
4059b7f5c055SJed Brown         /* layer 5 */
40609371c9d4SSatish Balay         {Kp,          Mp,          Sp,          Rp         },
40619371c9d4SSatish Balay         {Mp,          Ip,          Qp,          Sp         },
40629371c9d4SSatish Balay         {Np,          Lp,          Rp,          Tp         },
40639371c9d4SSatish Balay         {Jp,          Np,          Tp,          Qp + 56 * 1},
40649371c9d4SSatish Balay         {Pp,          Jp + 56 * 2, Qp + 56 * 3, Up         },
40659371c9d4SSatish Balay         {Lp,          Pp,          Up,          Rp         },
40669371c9d4SSatish Balay         {Op,          Kp,          Rp,          Vp         },
40679371c9d4SSatish Balay         {Ip + 56 * 2, Op,          Vp,          Qp + 56 * 2},
4068b7f5c055SJed Brown         /* layer 6 */
40699371c9d4SSatish Balay         {Rp,          Sp,          Aq,          Yp         },
40709371c9d4SSatish Balay         {Sp,          Qp,          Wp,          Aq         },
40719371c9d4SSatish Balay         {Tp,          Rp,          Yp,          Cq         },
40729371c9d4SSatish Balay         {Qp + 56 * 1, Tp,          Cq,          Wp + 56 * 1},
40739371c9d4SSatish Balay         {Up,          Qp + 56 * 3, Xp + 56 * 1, Dq         },
40749371c9d4SSatish Balay         {Rp,          Up,          Dq,          Zp         },
40759371c9d4SSatish Balay         {Vp,          Rp,          Zp,          Bq         },
40769371c9d4SSatish Balay         {Qp + 56 * 2, Vp,          Bq,          Xp         },
4077b7f5c055SJed Brown         /* layer 7 (the top is the periodic image of the bottom of layer 0) */
40789371c9d4SSatish Balay         {Yp,          Aq,          C + 56 * 4,  A + 56 * 4 },
40799371c9d4SSatish Balay         {Aq,          Wp,          B + 56 * 4,  C + 56 * 4 },
40809371c9d4SSatish Balay         {Cq,          Yp,          A + 56 * 4,  D + 56 * 4 },
40819371c9d4SSatish Balay         {Wp + 56 * 1, Cq,          D + 56 * 4,  B + 56 * 5 },
40829371c9d4SSatish Balay         {Dq,          Xp + 56 * 1, B + 56 * 5,  E + 56 * 4 },
40839371c9d4SSatish Balay         {Zp,          Dq,          E + 56 * 4,  A + 56 * 6 },
40849371c9d4SSatish Balay         {Bq,          Zp,          A + 56 * 6,  F + 56 * 4 },
40859371c9d4SSatish Balay         {Xp,          Bq,          F + 56 * 4,  B + 56 * 4 }
4086b7f5c055SJed Brown       };
4087b7f5c055SJed Brown       const PetscReal gamma                = PetscAcosReal((PetscSqrtReal(3.) - 1.) / PetscSqrtReal(2.)) / PETSC_PI;
40889371c9d4SSatish Balay       const PetscReal patternCoords[56][3] = {
4089bee3fc89SBarry Smith         {1.,        0.,        0.  }, /* A  */
4090bee3fc89SBarry Smith         {0.,        1.,        0.  }, /* B  */
4091bee3fc89SBarry Smith         {gamma,     gamma,     0.  }, /* C  */
4092bee3fc89SBarry Smith         {1 + gamma, 1 - gamma, 0.  }, /* D  */
4093bee3fc89SBarry Smith         {2 - gamma, 2 - gamma, 0.  }, /* E  */
4094bee3fc89SBarry Smith         {1 - gamma, 1 + gamma, 0.  }, /* F  */
4095b7f5c055SJed Brown 
4096bee3fc89SBarry Smith         {.5,        0,         .25 }, /* G  */
4097bee3fc89SBarry Smith         {1.5,       0.,        .25 }, /* H  */
4098bee3fc89SBarry Smith         {.5,        1.,        .25 }, /* II */
4099bee3fc89SBarry Smith         {1.5,       1.,        .25 }, /* J  */
4100bee3fc89SBarry Smith         {.25,       .5,        .25 }, /* K  */
4101bee3fc89SBarry Smith         {1.25,      .5,        .25 }, /* L  */
4102bee3fc89SBarry Smith         {.75,       1.5,       .25 }, /* M  */
4103bee3fc89SBarry Smith         {1.75,      1.5,       .25 }, /* N  */
4104b7f5c055SJed Brown 
4105bee3fc89SBarry Smith         {0.,        0.,        .5  }, /* O  */
4106bee3fc89SBarry Smith         {1.,        1.,        .5  }, /* P  */
4107bee3fc89SBarry Smith         {gamma,     1 - gamma, .5  }, /* Q  */
4108bee3fc89SBarry Smith         {1 + gamma, gamma,     .5  }, /* R  */
4109bee3fc89SBarry Smith         {2 - gamma, 1 + gamma, .5  }, /* S  */
4110bee3fc89SBarry Smith         {1 - gamma, 2 - gamma, .5  }, /* T  */
4111b7f5c055SJed Brown 
4112bee3fc89SBarry Smith         {0.,        .5,        .75 }, /* U  */
4113bee3fc89SBarry Smith         {0.,        1.5,       .75 }, /* V  */
4114bee3fc89SBarry Smith         {1.,        .5,        .75 }, /* W  */
4115bee3fc89SBarry Smith         {1.,        1.5,       .75 }, /* X  */
4116bee3fc89SBarry Smith         {.5,        .75,       .75 }, /* Y  */
4117bee3fc89SBarry Smith         {.5,        1.75,      .75 }, /* Z  */
4118bee3fc89SBarry Smith         {1.5,       .25,       .75 }, /* Ap */
4119bee3fc89SBarry Smith         {1.5,       1.25,      .75 }, /* Bp */
4120b7f5c055SJed Brown 
4121bee3fc89SBarry Smith         {1.,        0.,        1.  }, /* Cp */
4122bee3fc89SBarry Smith         {0.,        1.,        1.  }, /* Dp */
4123bee3fc89SBarry Smith         {1 - gamma, 1 - gamma, 1.  }, /* Ep */
4124bee3fc89SBarry Smith         {1 + gamma, 1 + gamma, 1.  }, /* Fp */
4125bee3fc89SBarry Smith         {2 - gamma, gamma,     1.  }, /* Gp */
4126bee3fc89SBarry Smith         {gamma,     2 - gamma, 1.  }, /* Hp */
4127b7f5c055SJed Brown 
4128bee3fc89SBarry Smith         {.5,        0.,        1.25}, /* Ip */
4129bee3fc89SBarry Smith         {1.5,       0.,        1.25}, /* Jp */
4130bee3fc89SBarry Smith         {.5,        1.,        1.25}, /* Kp */
4131bee3fc89SBarry Smith         {1.5,       1.,        1.25}, /* Lp */
4132bee3fc89SBarry Smith         {.75,       .5,        1.25}, /* Mp */
4133bee3fc89SBarry Smith         {1.75,      .5,        1.25}, /* Np */
4134bee3fc89SBarry Smith         {.25,       1.5,       1.25}, /* Op */
4135bee3fc89SBarry Smith         {1.25,      1.5,       1.25}, /* Pp */
4136b7f5c055SJed Brown 
4137bee3fc89SBarry Smith         {0.,        0.,        1.5 }, /* Qp */
4138bee3fc89SBarry Smith         {1.,        1.,        1.5 }, /* Rp */
4139bee3fc89SBarry Smith         {1 - gamma, gamma,     1.5 }, /* Sp */
4140bee3fc89SBarry Smith         {2 - gamma, 1 - gamma, 1.5 }, /* Tp */
4141bee3fc89SBarry Smith         {1 + gamma, 2 - gamma, 1.5 }, /* Up */
4142bee3fc89SBarry Smith         {gamma,     1 + gamma, 1.5 }, /* Vp */
4143b7f5c055SJed Brown 
4144bee3fc89SBarry Smith         {0.,        .5,        1.75}, /* Wp */
4145bee3fc89SBarry Smith         {0.,        1.5,       1.75}, /* Xp */
4146bee3fc89SBarry Smith         {1.,        .5,        1.75}, /* Yp */
4147bee3fc89SBarry Smith         {1.,        1.5,       1.75}, /* Zp */
4148bee3fc89SBarry Smith         {.5,        .25,       1.75}, /* Aq */
4149bee3fc89SBarry Smith         {.5,        1.25,      1.75}, /* Bq */
4150bee3fc89SBarry Smith         {1.5,       .75,       1.75}, /* Cq */
4151bee3fc89SBarry Smith         {1.5,       1.75,      1.75}, /* Dq */
4152b7f5c055SJed Brown       };
4153b7f5c055SJed Brown       PetscInt (*cells)[64][4] = NULL;
4154b7f5c055SJed Brown       PetscBool *seen;
4155b7f5c055SJed Brown       PetscInt  *vertToTrueVert;
4156b7f5c055SJed Brown       PetscInt   count;
4157b7f5c055SJed Brown 
4158b7f5c055SJed Brown       for (PetscInt i = 0; i < 3; i++) extentPlus[i] = extent[i] + 1;
4159b7f5c055SJed Brown       numBlocks = 1;
4160b7f5c055SJed Brown       for (PetscInt i = 0; i < 3; i++) numBlocks *= extent[i];
4161b7f5c055SJed Brown       numBlocksPlus = 1;
4162b7f5c055SJed Brown       for (PetscInt i = 0; i < 3; i++) numBlocksPlus *= extentPlus[i];
4163b7f5c055SJed Brown       numFaces = numBlocks * facesPerBlock;
41649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numBlocks, &cells));
41659566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(numBlocksPlus * vertsPerBlock, &seen));
4166b7f5c055SJed Brown       for (PetscInt k = 0; k < extent[2]; k++) {
4167b7f5c055SJed Brown         for (PetscInt j = 0; j < extent[1]; j++) {
4168b7f5c055SJed Brown           for (PetscInt i = 0; i < extent[0]; i++) {
4169b7f5c055SJed Brown             for (PetscInt f = 0; f < facesPerBlock; f++) {
4170b7f5c055SJed Brown               for (PetscInt v = 0; v < 4; v++) {
4171b7f5c055SJed Brown                 PetscInt vertRaw     = pattern[f][v];
4172b7f5c055SJed Brown                 PetscInt blockidx    = vertRaw / 56;
4173b7f5c055SJed Brown                 PetscInt patternvert = vertRaw % 56;
4174b7f5c055SJed Brown                 PetscInt xplus       = (blockidx & 1);
4175b7f5c055SJed Brown                 PetscInt yplus       = (blockidx & 2) >> 1;
4176b7f5c055SJed Brown                 PetscInt zplus       = (blockidx & 4) >> 2;
4177b7f5c055SJed Brown                 PetscInt zcoord      = (periodic && periodic[2] == DM_BOUNDARY_PERIODIC) ? ((k + zplus) % extent[2]) : (k + zplus);
4178b7f5c055SJed Brown                 PetscInt ycoord      = (periodic && periodic[1] == DM_BOUNDARY_PERIODIC) ? ((j + yplus) % extent[1]) : (j + yplus);
4179b7f5c055SJed Brown                 PetscInt xcoord      = (periodic && periodic[0] == DM_BOUNDARY_PERIODIC) ? ((i + xplus) % extent[0]) : (i + xplus);
4180b7f5c055SJed Brown                 PetscInt vert        = ((zcoord * extentPlus[1] + ycoord) * extentPlus[0] + xcoord) * 56 + patternvert;
4181b7f5c055SJed Brown 
4182b7f5c055SJed Brown                 cells[(k * extent[1] + j) * extent[0] + i][f][v] = vert;
4183b7f5c055SJed Brown                 seen[vert]                                       = PETSC_TRUE;
4184b7f5c055SJed Brown               }
4185b7f5c055SJed Brown             }
4186b7f5c055SJed Brown           }
4187b7f5c055SJed Brown         }
4188b7f5c055SJed Brown       }
41899371c9d4SSatish Balay       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++)
41909371c9d4SSatish Balay         if (seen[i]) numVertices++;
4191b7f5c055SJed Brown       count = 0;
41929566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numBlocksPlus * vertsPerBlock, &vertToTrueVert));
41939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numVertices * 3, &vtxCoords));
4194b7f5c055SJed Brown       for (PetscInt i = 0; i < numBlocksPlus * vertsPerBlock; i++) vertToTrueVert[i] = -1;
4195b7f5c055SJed Brown       for (PetscInt k = 0; k < extentPlus[2]; k++) {
4196b7f5c055SJed Brown         for (PetscInt j = 0; j < extentPlus[1]; j++) {
4197b7f5c055SJed Brown           for (PetscInt i = 0; i < extentPlus[0]; i++) {
4198b7f5c055SJed Brown             for (PetscInt v = 0; v < vertsPerBlock; v++) {
4199b7f5c055SJed Brown               PetscInt vIdx = ((k * extentPlus[1] + j) * extentPlus[0] + i) * vertsPerBlock + v;
4200b7f5c055SJed Brown 
4201b7f5c055SJed Brown               if (seen[vIdx]) {
4202b7f5c055SJed Brown                 PetscInt thisVert;
4203b7f5c055SJed Brown 
4204b7f5c055SJed Brown                 vertToTrueVert[vIdx] = thisVert = count++;
4205b7f5c055SJed Brown 
4206b7f5c055SJed Brown                 for (PetscInt d = 0; d < 3; d++) vtxCoords[3 * thisVert + d] = patternCoords[v][d];
4207b7f5c055SJed Brown                 vtxCoords[3 * thisVert + 0] += i * 2;
4208b7f5c055SJed Brown                 vtxCoords[3 * thisVert + 1] += j * 2;
4209b7f5c055SJed Brown                 vtxCoords[3 * thisVert + 2] += k * 2;
4210b7f5c055SJed Brown               }
4211b7f5c055SJed Brown             }
4212b7f5c055SJed Brown           }
4213b7f5c055SJed Brown         }
4214b7f5c055SJed Brown       }
4215b7f5c055SJed Brown       for (PetscInt i = 0; i < numBlocks; i++) {
4216b7f5c055SJed Brown         for (PetscInt f = 0; f < facesPerBlock; f++) {
4217ad540459SPierre Jolivet           for (PetscInt v = 0; v < 4; v++) cells[i][f][v] = vertToTrueVert[cells[i][f][v]];
4218b7f5c055SJed Brown         }
4219b7f5c055SJed Brown       }
42209566063dSJacob Faibussowitsch       PetscCall(PetscFree(vertToTrueVert));
42219566063dSJacob Faibussowitsch       PetscCall(PetscFree(seen));
4222b7f5c055SJed Brown       cells_flat = cells[0][0];
4223b7f5c055SJed Brown       numEdges   = 0;
4224b7f5c055SJed Brown       for (PetscInt i = 0; i < numFaces; i++) {
4225b7f5c055SJed Brown         for (PetscInt e = 0; e < 4; e++) {
4226b7f5c055SJed Brown           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
4227b7f5c055SJed Brown           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
4228b7f5c055SJed Brown 
4229b7f5c055SJed Brown           for (PetscInt d = 0; d < 3; d++) {
4230b7f5c055SJed Brown             if (!periodic || periodic[0] != DM_BOUNDARY_PERIODIC) {
4231b7f5c055SJed Brown               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) numEdges++;
4232b7f5c055SJed Brown               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) numEdges++;
4233b7f5c055SJed Brown             }
4234b7f5c055SJed Brown           }
4235b7f5c055SJed Brown         }
4236b7f5c055SJed Brown       }
42379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numEdges, &edges));
42389566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numEdges, &edgeSets));
4239b7f5c055SJed Brown       for (PetscInt edge = 0, i = 0; i < numFaces; i++) {
4240b7f5c055SJed Brown         for (PetscInt e = 0; e < 4; e++) {
4241b7f5c055SJed Brown           PetscInt         ev[]       = {cells_flat[i * 4 + e], cells_flat[i * 4 + ((e + 1) % 4)]};
4242b7f5c055SJed Brown           const PetscReal *evCoords[] = {&vtxCoords[3 * ev[0]], &vtxCoords[3 * ev[1]]};
4243b7f5c055SJed Brown 
4244b7f5c055SJed Brown           for (PetscInt d = 0; d < 3; d++) {
4245b7f5c055SJed Brown             if (!periodic || periodic[d] != DM_BOUNDARY_PERIODIC) {
4246b7f5c055SJed Brown               if (evCoords[0][d] == 0. && evCoords[1][d] == 0.) {
4247b7f5c055SJed Brown                 edges[edge][0]   = ev[0];
4248b7f5c055SJed Brown                 edges[edge][1]   = ev[1];
4249b7f5c055SJed Brown                 edgeSets[edge++] = 2 * d;
4250b7f5c055SJed Brown               }
4251b7f5c055SJed Brown               if (evCoords[0][d] == 2. * extent[d] && evCoords[1][d] == 2. * extent[d]) {
4252b7f5c055SJed Brown                 edges[edge][0]   = ev[0];
4253b7f5c055SJed Brown                 edges[edge][1]   = ev[1];
4254b7f5c055SJed Brown                 edgeSets[edge++] = 2 * d + 1;
4255b7f5c055SJed Brown               }
4256b7f5c055SJed Brown             }
4257b7f5c055SJed Brown           }
4258b7f5c055SJed Brown         }
4259b7f5c055SJed Brown       }
4260b7f5c055SJed Brown     }
4261b7f5c055SJed Brown     evalFunc   = TPSEvaluate_Gyroid;
42624663dae6SJed Brown     normalFunc = TPSExtrudeNormalFunc_Gyroid;
4263b7f5c055SJed Brown     break;
4264b7f5c055SJed Brown   }
4265b7f5c055SJed Brown 
42669566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, topoDim));
4267c5853193SPierre Jolivet   if (rank == 0) PetscCall(DMPlexBuildFromCellList(dm, numFaces, numVertices, 4, cells_flat));
42689566063dSJacob Faibussowitsch   else PetscCall(DMPlexBuildFromCellList(dm, 0, 0, 0, NULL));
42699566063dSJacob Faibussowitsch   PetscCall(PetscFree(cells_flat));
4270b7f5c055SJed Brown   {
4271b7f5c055SJed Brown     DM idm;
42729566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(dm, &idm));
427369d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &idm));
4274b7f5c055SJed Brown   }
4275c5853193SPierre Jolivet   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, vtxCoords));
42769566063dSJacob Faibussowitsch   else PetscCall(DMPlexBuildCoordinatesFromCellList(dm, spaceDim, NULL));
42779566063dSJacob Faibussowitsch   PetscCall(PetscFree(vtxCoords));
4278b7f5c055SJed Brown 
42799566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "Face Sets"));
42809566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "Face Sets", &label));
4281b7f5c055SJed Brown   for (PetscInt e = 0; e < numEdges; e++) {
4282b7f5c055SJed Brown     PetscInt        njoin;
4283b7f5c055SJed Brown     const PetscInt *join, verts[] = {numFaces + edges[e][0], numFaces + edges[e][1]};
42849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetJoin(dm, 2, verts, &njoin, &join));
428563a3b9bcSJacob Faibussowitsch     PetscCheck(njoin == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected unique join of vertices %" PetscInt_FMT " and %" PetscInt_FMT, edges[e][0], edges[e][1]);
42869566063dSJacob Faibussowitsch     PetscCall(DMLabelSetValue(label, join[0], edgeSets[e]));
42879566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreJoin(dm, 2, verts, &njoin, &join));
4288b7f5c055SJed Brown   }
42899566063dSJacob Faibussowitsch   PetscCall(PetscFree(edges));
42909566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgeSets));
42911436d7faSJed Brown   if (tps_distribute) {
42921436d7faSJed Brown     DM               pdm = NULL;
42931436d7faSJed Brown     PetscPartitioner part;
42941436d7faSJed Brown 
42959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPartitioner(dm, &part));
42969566063dSJacob Faibussowitsch     PetscCall(PetscPartitionerSetFromOptions(part));
42979566063dSJacob Faibussowitsch     PetscCall(DMPlexDistribute(dm, 0, NULL, &pdm));
429848a46eb9SPierre Jolivet     if (pdm) PetscCall(DMPlexReplace_Internal(dm, &pdm));
42991436d7faSJed Brown     // Do not auto-distribute again
43009566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeSetDefault(dm, PETSC_FALSE));
43011436d7faSJed Brown   }
4302b7f5c055SJed Brown 
43039566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
4304b7f5c055SJed Brown   for (PetscInt refine = 0; refine < refinements; refine++) {
4305b7f5c055SJed Brown     PetscInt     m;
4306f1d4225fSZach Atkins     DM           dmf, cdm, cdmf;
4307b7f5c055SJed Brown     Vec          X;
4308b7f5c055SJed Brown     PetscScalar *x;
4309f1d4225fSZach Atkins 
43109566063dSJacob Faibussowitsch     PetscCall(DMRefine(dm, MPI_COMM_NULL, &dmf));
4311f1d4225fSZach Atkins     PetscCall(DMGetCoordinateDM(dm, &cdm));
4312f1d4225fSZach Atkins     PetscCall(DMGetCoordinateDM(dmf, &cdmf));
4313f1d4225fSZach Atkins     PetscCall(DMCopyDisc(cdm, cdmf));
431469d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &dmf));
4315b7f5c055SJed Brown 
43169566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &X));
43179566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(X, &m));
43189566063dSJacob Faibussowitsch     PetscCall(VecGetArray(X, &x));
431948a46eb9SPierre Jolivet     for (PetscInt i = 0; i < m; i += 3) PetscCall(TPSNearestPoint(evalFunc, &x[i]));
43209566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(X, &x));
4321b7f5c055SJed Brown   }
4322b7f5c055SJed Brown 
4323b7f5c055SJed Brown   // Face Sets has already been propagated to new vertices during refinement; this propagates to the initial vertices.
43249566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "Face Sets", &label));
43259566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, label));
4326b7f5c055SJed Brown 
432746139095SJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_Generate, dm, 0, 0, 0));
432846139095SJed Brown 
4329b7f5c055SJed Brown   if (thickness > 0) {
43304663dae6SJed Brown     DM              edm, cdm, ecdm;
43314663dae6SJed Brown     DMPlexTransform tr;
43324663dae6SJed Brown     const char     *prefix;
43334663dae6SJed Brown     PetscOptions    options;
43344663dae6SJed Brown     // Code from DMPlexExtrude
43354663dae6SJed Brown     PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr));
43364663dae6SJed Brown     PetscCall(DMPlexTransformSetDM(tr, dm));
4337ce78bad3SBarry Smith     PetscCall(DMPlexTransformSetType(tr, DMPLEXEXTRUDETYPE));
43384663dae6SJed Brown     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
43394663dae6SJed Brown     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix));
43404663dae6SJed Brown     PetscCall(PetscObjectGetOptions((PetscObject)dm, &options));
43414663dae6SJed Brown     PetscCall(PetscObjectSetOptions((PetscObject)tr, options));
43424663dae6SJed Brown     PetscCall(DMPlexTransformExtrudeSetLayers(tr, layers));
43434663dae6SJed Brown     PetscCall(DMPlexTransformExtrudeSetThickness(tr, thickness));
43444663dae6SJed Brown     PetscCall(DMPlexTransformExtrudeSetTensor(tr, PETSC_FALSE));
43454663dae6SJed Brown     PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, PETSC_TRUE));
43464663dae6SJed Brown     PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc));
43474663dae6SJed Brown     PetscCall(DMPlexTransformSetFromOptions(tr));
43484663dae6SJed Brown     PetscCall(PetscObjectSetOptions((PetscObject)tr, NULL));
43494663dae6SJed Brown     PetscCall(DMPlexTransformSetUp(tr));
43504663dae6SJed Brown     PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_tps_transform_view"));
43514663dae6SJed Brown     PetscCall(DMPlexTransformApply(tr, dm, &edm));
43524663dae6SJed Brown     PetscCall(DMCopyDisc(dm, edm));
43534663dae6SJed Brown     PetscCall(DMGetCoordinateDM(dm, &cdm));
43544663dae6SJed Brown     PetscCall(DMGetCoordinateDM(edm, &ecdm));
43554663dae6SJed Brown     PetscCall(DMCopyDisc(cdm, ecdm));
43564663dae6SJed Brown     PetscCall(DMPlexTransformCreateDiscLabels(tr, edm));
43574663dae6SJed Brown     PetscCall(DMPlexTransformDestroy(&tr));
4358a77a5016SMatthew G. Knepley     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, edm));
435969d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &edm));
4360b7f5c055SJed Brown   }
43613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4362b7f5c055SJed Brown }
4363b7f5c055SJed Brown 
4364b7f5c055SJed Brown /*@
4365b7f5c055SJed Brown   DMPlexCreateTPSMesh - Create a distributed, interpolated mesh of a triply-periodic surface
4366b7f5c055SJed Brown 
4367b7f5c055SJed Brown   Collective
4368b7f5c055SJed Brown 
4369b7f5c055SJed Brown   Input Parameters:
4370a1cb98faSBarry Smith + comm           - The communicator for the `DM` object
4371b7f5c055SJed Brown . tpstype        - Type of triply-periodic surface
4372b7f5c055SJed Brown . extent         - Array of length 3 containing number of periods in each direction
437320f4b53cSBarry Smith . periodic       - array of length 3 with periodicity, or `NULL` for non-periodic
43741436d7faSJed Brown . tps_distribute - Distribute 2D manifold mesh prior to refinement and extrusion (more scalable)
4375817da375SSatish Balay . refinements    - Number of factor-of-2 refinements of 2D manifold mesh
43761436d7faSJed Brown . layers         - Number of cell layers extruded in normal direction
4377817da375SSatish Balay - thickness      - Thickness in normal direction
4378b7f5c055SJed Brown 
4379b7f5c055SJed Brown   Output Parameter:
4380a1cb98faSBarry Smith . dm - The `DM` object
4381a1cb98faSBarry Smith 
4382a1cb98faSBarry Smith   Level: beginner
4383b7f5c055SJed Brown 
4384b7f5c055SJed Brown   Notes:
438515229ffcSPierre Jolivet   This meshes the surface of the Schwarz P or Gyroid surfaces.  Schwarz P is the simplest member of the triply-periodic minimal surfaces.
43861d27aa22SBarry Smith   <https://en.wikipedia.org/wiki/Schwarz_minimal_surface#Schwarz_P_(%22Primitive%22)> and can be cut with "clean" boundaries.
43871d27aa22SBarry Smith   The Gyroid <https://en.wikipedia.org/wiki/Gyroid> is another triply-periodic minimal surface with applications in additive manufacturing; it is much more difficult to "cut" since there are no planes of symmetry.
4388b7f5c055SJed Brown   Our implementation creates a very coarse mesh of the surface and refines (by 4-way splitting) as many times as requested.
4389b7f5c055SJed Brown   On each refinement, all vertices are projected to their nearest point on the surface.
4390b7f5c055SJed Brown   This projection could readily be extended to related surfaces.
4391b7f5c055SJed Brown 
43921d27aa22SBarry Smith   See {cite}`maskery2018insights`
43931d27aa22SBarry Smith 
43941d27aa22SBarry Smith   The face (edge) sets for the Schwarz P surface are numbered $1(-x), 2(+x), 3(-y), 4(+y), 5(-z), 6(+z)$.
43951d27aa22SBarry Smith   When the mesh is refined, "Face Sets" contain the new vertices (created during refinement).
43961d27aa22SBarry Smith   Use `DMPlexLabelComplete()` to propagate to coarse-level vertices.
4397b7f5c055SJed Brown 
439860225df5SJacob Faibussowitsch   Developer Notes:
4399b7f5c055SJed Brown   The Gyroid mesh does not currently mark boundary sets.
4400b7f5c055SJed Brown 
44011cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMSetType()`, `DMCreate()`
4402b7f5c055SJed Brown @*/
4403d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateTPSMesh(MPI_Comm comm, DMPlexTPSType tpstype, const PetscInt extent[], const DMBoundaryType periodic[], PetscBool tps_distribute, PetscInt refinements, PetscInt layers, PetscReal thickness, DM *dm)
4404d71ae5a4SJacob Faibussowitsch {
4405b7f5c055SJed Brown   PetscFunctionBegin;
44069566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
44079566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
44089566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateTPSMesh_Internal(*dm, tpstype, extent, periodic, tps_distribute, refinements, layers, thickness));
44093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4410b7f5c055SJed Brown }
4411b7f5c055SJed Brown 
44129318fe57SMatthew G. Knepley /*@
44139318fe57SMatthew G. Knepley   DMPlexCreateSphereMesh - Creates a mesh on the d-dimensional sphere, S^d.
44149318fe57SMatthew G. Knepley 
44159318fe57SMatthew G. Knepley   Collective
44169318fe57SMatthew G. Knepley 
44179318fe57SMatthew G. Knepley   Input Parameters:
4418a1cb98faSBarry Smith + comm    - The communicator for the `DM` object
44199318fe57SMatthew G. Knepley . dim     - The dimension
44209318fe57SMatthew G. Knepley . simplex - Use simplices, or tensor product cells
44219318fe57SMatthew G. Knepley - R       - The radius
44229318fe57SMatthew G. Knepley 
44239318fe57SMatthew G. Knepley   Output Parameter:
4424a1cb98faSBarry Smith . dm - The `DM` object
44259318fe57SMatthew G. Knepley 
44269318fe57SMatthew G. Knepley   Level: beginner
44279318fe57SMatthew G. Knepley 
44281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBallMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
44299318fe57SMatthew G. Knepley @*/
4430d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateSphereMesh(MPI_Comm comm, PetscInt dim, PetscBool simplex, PetscReal R, DM *dm)
4431d71ae5a4SJacob Faibussowitsch {
44329318fe57SMatthew G. Knepley   PetscFunctionBegin;
44334f572ea9SToby Isaac   PetscAssertPointer(dm, 5);
44349566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
44359566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
44369566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateSphereMesh_Internal(*dm, dim, simplex, R));
44373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44389318fe57SMatthew G. Knepley }
44399318fe57SMatthew G. Knepley 
4440d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBallMesh_Internal(DM dm, PetscInt dim, PetscReal R)
4441d71ae5a4SJacob Faibussowitsch {
44429318fe57SMatthew G. Knepley   DM          sdm, vol;
44439318fe57SMatthew G. Knepley   DMLabel     bdlabel;
4444dd2b43ebSStefano Zampini   const char *prefix;
44459318fe57SMatthew G. Knepley 
44469318fe57SMatthew G. Knepley   PetscFunctionBegin;
44479566063dSJacob Faibussowitsch   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
44489566063dSJacob Faibussowitsch   PetscCall(DMSetType(sdm, DMPLEX));
4449dd2b43ebSStefano Zampini   PetscCall(DMGetOptionsPrefix(dm, &prefix));
4450dd2b43ebSStefano Zampini   PetscCall(DMSetOptionsPrefix(sdm, prefix));
4451dd2b43ebSStefano Zampini   PetscCall(DMAppendOptionsPrefix(sdm, "bd_"));
4452dd2b43ebSStefano Zampini   PetscCall(DMPlexDistributeSetDefault(sdm, PETSC_FALSE));
44539566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateSphereMesh_Internal(sdm, dim - 1, PETSC_TRUE, R));
44549566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(sdm));
44559566063dSJacob Faibussowitsch   PetscCall(DMViewFromOptions(sdm, NULL, "-dm_view"));
44569566063dSJacob Faibussowitsch   PetscCall(DMPlexGenerate(sdm, NULL, PETSC_TRUE, &vol));
44579566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sdm));
445869d8a87bSksagiyam   PetscCall(DMPlexReplace_Internal(dm, &vol));
44599566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, "marker"));
44609566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "marker", &bdlabel));
44619566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, PETSC_DETERMINE, bdlabel));
44629566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, bdlabel));
44633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
446451a74b61SMatthew G. Knepley }
446551a74b61SMatthew G. Knepley 
446651a74b61SMatthew G. Knepley /*@
446751a74b61SMatthew G. Knepley   DMPlexCreateBallMesh - Creates a simplex mesh on the d-dimensional ball, B^d.
446851a74b61SMatthew G. Knepley 
446951a74b61SMatthew G. Knepley   Collective
447051a74b61SMatthew G. Knepley 
447151a74b61SMatthew G. Knepley   Input Parameters:
4472a1cb98faSBarry Smith + comm - The communicator for the `DM` object
447351a74b61SMatthew G. Knepley . dim  - The dimension
447451a74b61SMatthew G. Knepley - R    - The radius
447551a74b61SMatthew G. Knepley 
447651a74b61SMatthew G. Knepley   Output Parameter:
4477a1cb98faSBarry Smith . dm - The `DM` object
447851a74b61SMatthew G. Knepley 
4479a1cb98faSBarry Smith   Options Database Key:
448060225df5SJacob Faibussowitsch . bd_dm_refine - This will refine the surface mesh preserving the sphere geometry
448151a74b61SMatthew G. Knepley 
448251a74b61SMatthew G. Knepley   Level: beginner
448351a74b61SMatthew G. Knepley 
44841cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSphereMesh()`, `DMPlexCreateBoxMesh()`, `DMSetType()`, `DMCreate()`
448551a74b61SMatthew G. Knepley @*/
4486d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBallMesh(MPI_Comm comm, PetscInt dim, PetscReal R, DM *dm)
4487d71ae5a4SJacob Faibussowitsch {
448851a74b61SMatthew G. Knepley   PetscFunctionBegin;
44899566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
44909566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
44919566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateBallMesh_Internal(*dm, dim, R));
44923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44932829fed8SMatthew G. Knepley }
44942829fed8SMatthew G. Knepley 
4495d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateReferenceCell_Internal(DM rdm, DMPolytopeType ct)
4496d71ae5a4SJacob Faibussowitsch {
44970a6ba040SMatthew G. Knepley   PetscFunctionBegin;
44989318fe57SMatthew G. Knepley   switch (ct) {
44999371c9d4SSatish Balay   case DM_POLYTOPE_POINT: {
45009318fe57SMatthew G. Knepley     PetscInt    numPoints[1]        = {1};
45019318fe57SMatthew G. Knepley     PetscInt    coneSize[1]         = {0};
45029318fe57SMatthew G. Knepley     PetscInt    cones[1]            = {0};
45039318fe57SMatthew G. Knepley     PetscInt    coneOrientations[1] = {0};
45049318fe57SMatthew G. Knepley     PetscScalar vertexCoords[1]     = {0.0};
45059318fe57SMatthew G. Knepley 
45069566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 0));
45079566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 0, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45089371c9d4SSatish Balay   } break;
45099371c9d4SSatish Balay   case DM_POLYTOPE_SEGMENT: {
45109318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {2, 1};
45119318fe57SMatthew G. Knepley     PetscInt    coneSize[3]         = {2, 0, 0};
45129318fe57SMatthew G. Knepley     PetscInt    cones[2]            = {1, 2};
45139318fe57SMatthew G. Knepley     PetscInt    coneOrientations[2] = {0, 0};
45149318fe57SMatthew G. Knepley     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
45159318fe57SMatthew G. Knepley 
45169566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 1));
45179566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45189371c9d4SSatish Balay   } break;
45199371c9d4SSatish Balay   case DM_POLYTOPE_POINT_PRISM_TENSOR: {
4520b5a892a1SMatthew G. Knepley     PetscInt    numPoints[2]        = {2, 1};
4521b5a892a1SMatthew G. Knepley     PetscInt    coneSize[3]         = {2, 0, 0};
4522b5a892a1SMatthew G. Knepley     PetscInt    cones[2]            = {1, 2};
4523b5a892a1SMatthew G. Knepley     PetscInt    coneOrientations[2] = {0, 0};
4524b5a892a1SMatthew G. Knepley     PetscScalar vertexCoords[2]     = {-1.0, 1.0};
4525b5a892a1SMatthew G. Knepley 
45269566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 1));
45279566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45289371c9d4SSatish Balay   } break;
45299371c9d4SSatish Balay   case DM_POLYTOPE_TRIANGLE: {
45309318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {3, 1};
45319318fe57SMatthew G. Knepley     PetscInt    coneSize[4]         = {3, 0, 0, 0};
45329318fe57SMatthew G. Knepley     PetscInt    cones[3]            = {1, 2, 3};
45339318fe57SMatthew G. Knepley     PetscInt    coneOrientations[3] = {0, 0, 0};
45349318fe57SMatthew G. Knepley     PetscScalar vertexCoords[6]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0};
45359318fe57SMatthew G. Knepley 
45369566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 2));
45379566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45389371c9d4SSatish Balay   } break;
45399371c9d4SSatish Balay   case DM_POLYTOPE_QUADRILATERAL: {
45409318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {4, 1};
45419318fe57SMatthew G. Knepley     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
45429318fe57SMatthew G. Knepley     PetscInt    cones[4]            = {1, 2, 3, 4};
45439318fe57SMatthew G. Knepley     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
45449318fe57SMatthew G. Knepley     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0};
45459318fe57SMatthew G. Knepley 
45469566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 2));
45479566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45489371c9d4SSatish Balay   } break;
45499371c9d4SSatish Balay   case DM_POLYTOPE_SEG_PRISM_TENSOR: {
45509318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {4, 1};
45519318fe57SMatthew G. Knepley     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
45529318fe57SMatthew G. Knepley     PetscInt    cones[4]            = {1, 2, 3, 4};
45539318fe57SMatthew G. Knepley     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
45549318fe57SMatthew G. Knepley     PetscScalar vertexCoords[8]     = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
45559318fe57SMatthew G. Knepley 
45569566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 2));
45579566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45589371c9d4SSatish Balay   } break;
45599371c9d4SSatish Balay   case DM_POLYTOPE_TETRAHEDRON: {
45609318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {4, 1};
45619318fe57SMatthew G. Knepley     PetscInt    coneSize[5]         = {4, 0, 0, 0, 0};
4562f0edb160SMatthew G. Knepley     PetscInt    cones[4]            = {1, 2, 3, 4};
45639318fe57SMatthew G. Knepley     PetscInt    coneOrientations[4] = {0, 0, 0, 0};
4564f0edb160SMatthew G. Knepley     PetscScalar vertexCoords[12]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0};
45659318fe57SMatthew G. Knepley 
45669566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
45679566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45689371c9d4SSatish Balay   } break;
45699371c9d4SSatish Balay   case DM_POLYTOPE_HEXAHEDRON: {
45709318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {8, 1};
45719318fe57SMatthew G. Knepley     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
4572f0edb160SMatthew G. Knepley     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
45739318fe57SMatthew G. Knepley     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
45749371c9d4SSatish Balay     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};
45759318fe57SMatthew G. Knepley 
45769566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
45779566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45789371c9d4SSatish Balay   } break;
45799371c9d4SSatish Balay   case DM_POLYTOPE_TRI_PRISM: {
45809318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {6, 1};
45819318fe57SMatthew G. Knepley     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
4582f0edb160SMatthew G. Knepley     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
45839318fe57SMatthew G. Knepley     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
45849371c9d4SSatish Balay     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};
45859318fe57SMatthew G. Knepley 
45869566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
45879566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45889371c9d4SSatish Balay   } break;
45899371c9d4SSatish Balay   case DM_POLYTOPE_TRI_PRISM_TENSOR: {
45909318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {6, 1};
45919318fe57SMatthew G. Knepley     PetscInt    coneSize[7]         = {6, 0, 0, 0, 0, 0, 0};
45929318fe57SMatthew G. Knepley     PetscInt    cones[6]            = {1, 2, 3, 4, 5, 6};
45939318fe57SMatthew G. Knepley     PetscInt    coneOrientations[6] = {0, 0, 0, 0, 0, 0};
45949371c9d4SSatish Balay     PetscScalar vertexCoords[18]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0};
45959318fe57SMatthew G. Knepley 
45969566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
45979566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
45989371c9d4SSatish Balay   } break;
45999371c9d4SSatish Balay   case DM_POLYTOPE_QUAD_PRISM_TENSOR: {
46009318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {8, 1};
46019318fe57SMatthew G. Knepley     PetscInt    coneSize[9]         = {8, 0, 0, 0, 0, 0, 0, 0, 0};
46029318fe57SMatthew G. Knepley     PetscInt    cones[8]            = {1, 2, 3, 4, 5, 6, 7, 8};
46039318fe57SMatthew G. Knepley     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
46049371c9d4SSatish Balay     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0};
46059318fe57SMatthew G. Knepley 
46069566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
46079566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
46089371c9d4SSatish Balay   } break;
46099371c9d4SSatish Balay   case DM_POLYTOPE_PYRAMID: {
46109318fe57SMatthew G. Knepley     PetscInt    numPoints[2]        = {5, 1};
46119318fe57SMatthew G. Knepley     PetscInt    coneSize[6]         = {5, 0, 0, 0, 0, 0};
4612f0edb160SMatthew G. Knepley     PetscInt    cones[5]            = {1, 2, 3, 4, 5};
46139318fe57SMatthew G. Knepley     PetscInt    coneOrientations[8] = {0, 0, 0, 0, 0, 0, 0, 0};
46149371c9d4SSatish Balay     PetscScalar vertexCoords[24]    = {-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0};
46159318fe57SMatthew G. Knepley 
46169566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(rdm, 3));
46179566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(rdm, 1, numPoints, coneSize, cones, coneOrientations, vertexCoords));
46189371c9d4SSatish Balay   } break;
4619d71ae5a4SJacob Faibussowitsch   default:
4620d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)rdm), PETSC_ERR_ARG_WRONG, "Cannot create reference cell for cell type %s", DMPolytopeTypes[ct]);
46219318fe57SMatthew G. Knepley   }
46229318fe57SMatthew G. Knepley   {
46239318fe57SMatthew G. Knepley     PetscInt Nv, v;
46249318fe57SMatthew G. Knepley 
46259318fe57SMatthew G. Knepley     /* Must create the celltype label here so that we do not automatically try to compute the types */
46269566063dSJacob Faibussowitsch     PetscCall(DMCreateLabel(rdm, "celltype"));
46279566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCellType(rdm, 0, ct));
46289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(rdm, NULL, &Nv));
46299566063dSJacob Faibussowitsch     for (v = 1; v < Nv; ++v) PetscCall(DMPlexSetCellType(rdm, v, DM_POLYTOPE_POINT));
46309318fe57SMatthew G. Knepley   }
46319566063dSJacob Faibussowitsch   PetscCall(DMPlexInterpolateInPlace_Internal(rdm));
46329566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)rdm, DMPolytopeTypes[ct]));
46333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46340a6ba040SMatthew G. Knepley }
46350a6ba040SMatthew G. Knepley 
46369318fe57SMatthew G. Knepley /*@
4637a1cb98faSBarry Smith   DMPlexCreateReferenceCell - Create a `DMPLEX` with the appropriate FEM reference cell
46389318fe57SMatthew G. Knepley 
46399318fe57SMatthew G. Knepley   Collective
46409318fe57SMatthew G. Knepley 
46419318fe57SMatthew G. Knepley   Input Parameters:
46429318fe57SMatthew G. Knepley + comm - The communicator
46439318fe57SMatthew G. Knepley - ct   - The cell type of the reference cell
46449318fe57SMatthew G. Knepley 
46459318fe57SMatthew G. Knepley   Output Parameter:
46469318fe57SMatthew G. Knepley . refdm - The reference cell
46479318fe57SMatthew G. Knepley 
46489318fe57SMatthew G. Knepley   Level: intermediate
46499318fe57SMatthew G. Knepley 
465042747ad1SJacob Faibussowitsch .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateBoxMesh()`
46519318fe57SMatthew G. Knepley @*/
4652d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateReferenceCell(MPI_Comm comm, DMPolytopeType ct, DM *refdm)
4653d71ae5a4SJacob Faibussowitsch {
46540a6ba040SMatthew G. Knepley   PetscFunctionBegin;
46559566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, refdm));
46569566063dSJacob Faibussowitsch   PetscCall(DMSetType(*refdm, DMPLEX));
46579566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell_Internal(*refdm, ct));
46583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46599318fe57SMatthew G. Knepley }
466079a015ccSMatthew G. Knepley 
4661d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateBoundaryLabel_Private(DM dm, const char name[])
4662d71ae5a4SJacob Faibussowitsch {
46639318fe57SMatthew G. Knepley   DM        plex;
46649318fe57SMatthew G. Knepley   DMLabel   label;
46659318fe57SMatthew G. Knepley   PetscBool hasLabel;
46660a6ba040SMatthew G. Knepley 
4667c22d3578SMatthew G. Knepley   PetscFunctionBegin;
46689566063dSJacob Faibussowitsch   PetscCall(DMHasLabel(dm, name, &hasLabel));
46693ba16761SJacob Faibussowitsch   if (hasLabel) PetscFunctionReturn(PETSC_SUCCESS);
46709566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(dm, name));
46719566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, name, &label));
46729566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
46739566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(plex, 1, label));
46741c8afea9SMatthew G. Knepley   PetscCall(DMPlexLabelComplete(plex, label));
46759566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
46763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46779318fe57SMatthew G. Knepley }
4678acdc6f61SToby Isaac 
4679669647acSMatthew G. Knepley /*
4680669647acSMatthew G. Knepley   We use the last coordinate as the radius, the inner radius is lower[dim-1] and the outer radius is upper[dim-1]. Then we map the first coordinate around the circle.
4681669647acSMatthew G. Knepley 
4682669647acSMatthew G. Knepley     (x, y) -> (r, theta) = (x[1], (x[0] - lower[0]) * 2\pi/(upper[0] - lower[0]))
4683669647acSMatthew G. Knepley */
4684d71ae5a4SJacob Faibussowitsch static void boxToAnnulus(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
4685d71ae5a4SJacob Faibussowitsch {
4686669647acSMatthew G. Knepley   const PetscReal low = PetscRealPart(constants[0]);
4687669647acSMatthew G. Knepley   const PetscReal upp = PetscRealPart(constants[1]);
4688669647acSMatthew G. Knepley   const PetscReal r   = PetscRealPart(u[1]);
4689669647acSMatthew G. Knepley   const PetscReal th  = 2. * PETSC_PI * (PetscRealPart(u[0]) - low) / (upp - low);
4690669647acSMatthew G. Knepley 
4691669647acSMatthew G. Knepley   f0[0] = r * PetscCosReal(th);
4692669647acSMatthew G. Knepley   f0[1] = r * PetscSinReal(th);
4693669647acSMatthew G. Knepley }
4694669647acSMatthew G. Knepley 
46955390be7dSMatthew G. Knepley // Insert vertices and their joins, marked by depth
46965390be7dSMatthew G. Knepley static PetscErrorCode ProcessCohesiveLabel_Vertices(DM dm, DMLabel label, DMLabel vlabel, PetscInt val, PetscInt n, const PetscInt vertices[])
46975390be7dSMatthew G. Knepley {
46985390be7dSMatthew G. Knepley   PetscFunctionBegin;
46995390be7dSMatthew G. Knepley   PetscCall(DMPlexMarkSubmesh_Interpolated(dm, vlabel, val, PETSC_FALSE, PETSC_FALSE, label, NULL));
47005390be7dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
47015390be7dSMatthew G. Knepley }
47025390be7dSMatthew G. Knepley 
47035390be7dSMatthew G. Knepley // Insert faces and their closures, marked by depth
47045390be7dSMatthew G. Knepley static PetscErrorCode ProcessCohesiveLabel_Faces(DM dm, DMLabel label, PetscInt n, const PetscInt faces[])
47055390be7dSMatthew G. Knepley {
47065390be7dSMatthew G. Knepley   PetscFunctionBegin;
47075390be7dSMatthew G. Knepley   for (PetscInt p = 0; p < n; ++p) {
47085390be7dSMatthew G. Knepley     const PetscInt point   = faces[p];
47095390be7dSMatthew G. Knepley     PetscInt      *closure = NULL;
47105390be7dSMatthew G. Knepley     PetscInt       clSize, pdepth;
47115390be7dSMatthew G. Knepley 
47125390be7dSMatthew G. Knepley     PetscCall(DMPlexGetPointDepth(dm, point, &pdepth));
47135390be7dSMatthew G. Knepley     PetscCall(DMLabelSetValue(label, point, pdepth));
47145390be7dSMatthew G. Knepley     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
47155390be7dSMatthew G. Knepley     for (PetscInt cl = 0; cl < clSize * 2; cl += 2) {
47165390be7dSMatthew G. Knepley       PetscCall(DMPlexGetPointDepth(dm, closure[cl], &pdepth));
47175390be7dSMatthew G. Knepley       PetscCall(DMLabelSetValue(label, closure[cl], pdepth));
47185390be7dSMatthew G. Knepley     }
47195390be7dSMatthew G. Knepley     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &clSize, &closure));
47205390be7dSMatthew G. Knepley   }
47215390be7dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
47225390be7dSMatthew G. Knepley }
47235390be7dSMatthew G. Knepley 
47244e22dd4cSMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);
47254e22dd4cSMatthew G. Knepley 
47265dca41c3SJed Brown const char *const DMPlexShapes[] = {"box", "box_surface", "ball", "sphere", "cylinder", "schwarz_p", "gyroid", "doublet", "annulus", "hypercubic", "zbox", "unknown", "DMPlexShape", "DM_SHAPE_", NULL};
47279318fe57SMatthew G. Knepley 
4728ce78bad3SBarry Smith static PetscErrorCode DMPlexCreateFromOptions_Internal(PetscOptionItems PetscOptionsObject, PetscBool *useCoordSpace, DM dm)
4729d71ae5a4SJacob Faibussowitsch {
47309318fe57SMatthew G. Knepley   DMPlexShape    shape   = DM_SHAPE_BOX;
47319318fe57SMatthew G. Knepley   DMPolytopeType cell    = DM_POLYTOPE_TRIANGLE;
47329318fe57SMatthew G. Knepley   PetscInt       dim     = 2;
4733b9da1bb3SMatthew G. Knepley   PetscBool      simplex = PETSC_TRUE, interpolate = PETSC_TRUE, orient = PETSC_FALSE, adjCone = PETSC_FALSE, adjClosure = PETSC_TRUE, refDomain = PETSC_FALSE;
4734d0812dedSMatthew G. Knepley   PetscBool      flg, flg2, fflg, strflg, bdfflg, nameflg;
47359318fe57SMatthew G. Knepley   MPI_Comm       comm;
4736ed5e4e85SVaclav Hapla   char           filename[PETSC_MAX_PATH_LEN]   = "<unspecified>";
4737ed5e4e85SVaclav Hapla   char           bdFilename[PETSC_MAX_PATH_LEN] = "<unspecified>";
4738ed5e4e85SVaclav Hapla   char           plexname[PETSC_MAX_PATH_LEN]   = "";
47394e22dd4cSMatthew G. Knepley   const char    *option;
47409318fe57SMatthew G. Knepley 
47419318fe57SMatthew G. Knepley   PetscFunctionBegin;
4742708be2fdSJed Brown   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
47439566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
47449318fe57SMatthew G. Knepley   /* TODO Turn this into a registration interface */
47459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-dm_plex_filename", "File containing a mesh", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &fflg));
4746d0812dedSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_plex_file_contents", "Contents of a file format in a string", "DMPlexCreateFromFile", filename, filename, sizeof(filename), &strflg));
47479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-dm_plex_boundary_filename", "File containing a mesh boundary", "DMPlexCreateFromFile", bdFilename, bdFilename, sizeof(bdFilename), &bdfflg));
47489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-dm_plex_name", "Name of the mesh in the file", "DMPlexCreateFromFile", plexname, plexname, sizeof(plexname), &nameflg));
47499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-dm_plex_cell", "Cell shape", "", DMPolytopeTypes, (PetscEnum)cell, (PetscEnum *)&cell, NULL));
47509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_reference_cell_domain", "Use a reference cell domain", "", refDomain, &refDomain, NULL));
47519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-dm_plex_shape", "Shape for built-in mesh", "", DMPlexShapes, (PetscEnum)shape, (PetscEnum *)&shape, &flg));
47529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_plex_dim", "Topological dimension of the mesh", "DMGetDimension", dim, &dim, &flg, 0));
47539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_simplex", "Mesh cell shape", "", simplex, &simplex, &flg));
47549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_interpolate", "Flag to create edges and faces automatically", "", interpolate, &interpolate, &flg));
4755b9da1bb3SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_orient", "Orient the constructed mesh", "DMPlexOrient", orient, &orient, &flg));
47569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_adj_cone", "Set adjacency direction", "DMSetBasicAdjacency", adjCone, &adjCone, &flg));
47579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_adj_closure", "Set adjacency size", "DMSetBasicAdjacency", adjClosure, &adjClosure, &flg2));
47589566063dSJacob Faibussowitsch   if (flg || flg2) PetscCall(DMSetBasicAdjacency(dm, adjCone, adjClosure));
47593f3e541fSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_adj", "Debug output level all adjacency computations", "", 0, &((DM_Plex *)dm->data)->printAdj, NULL, 0));
47609318fe57SMatthew G. Knepley 
476161a622f3SMatthew G. Knepley   switch (cell) {
476261a622f3SMatthew G. Knepley   case DM_POLYTOPE_POINT:
476361a622f3SMatthew G. Knepley   case DM_POLYTOPE_SEGMENT:
476461a622f3SMatthew G. Knepley   case DM_POLYTOPE_POINT_PRISM_TENSOR:
476561a622f3SMatthew G. Knepley   case DM_POLYTOPE_TRIANGLE:
476661a622f3SMatthew G. Knepley   case DM_POLYTOPE_QUADRILATERAL:
476761a622f3SMatthew G. Knepley   case DM_POLYTOPE_TETRAHEDRON:
4768d71ae5a4SJacob Faibussowitsch   case DM_POLYTOPE_HEXAHEDRON:
4769d71ae5a4SJacob Faibussowitsch     *useCoordSpace = PETSC_TRUE;
4770d71ae5a4SJacob Faibussowitsch     break;
4771d71ae5a4SJacob Faibussowitsch   default:
4772d71ae5a4SJacob Faibussowitsch     *useCoordSpace = PETSC_FALSE;
4773d71ae5a4SJacob Faibussowitsch     break;
477461a622f3SMatthew G. Knepley   }
477561a622f3SMatthew G. Knepley 
47769318fe57SMatthew G. Knepley   if (fflg) {
47779318fe57SMatthew G. Knepley     DM          dmnew;
47781e4a82c4SMatthew G. Knepley     const char *name;
47799318fe57SMatthew G. Knepley 
47801e4a82c4SMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
47811e4a82c4SMatthew G. Knepley     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), filename, nameflg ? plexname : name, interpolate, &dmnew));
47825de52c6dSVaclav Hapla     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
478369d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
47849318fe57SMatthew G. Knepley   } else if (refDomain) {
47859566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell_Internal(dm, cell));
47869318fe57SMatthew G. Knepley   } else if (bdfflg) {
47879318fe57SMatthew G. Knepley     DM          bdm, dmnew;
47881e4a82c4SMatthew G. Knepley     const char *name;
47899318fe57SMatthew G. Knepley 
47901e4a82c4SMatthew G. Knepley     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
47911e4a82c4SMatthew G. Knepley     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), bdFilename, nameflg ? plexname : name, interpolate, &bdm));
47929566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)bdm, "bd_"));
47939566063dSJacob Faibussowitsch     PetscCall(DMSetFromOptions(bdm));
47949566063dSJacob Faibussowitsch     PetscCall(DMPlexGenerate(bdm, NULL, interpolate, &dmnew));
47959566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&bdm));
47965de52c6dSVaclav Hapla     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
479769d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
4798d0812dedSMatthew G. Knepley   } else if (strflg) {
4799d0812dedSMatthew G. Knepley     DM          dmnew;
4800d0812dedSMatthew G. Knepley     PetscViewer viewer;
4801d0812dedSMatthew G. Knepley     const char *contents;
4802d0812dedSMatthew G. Knepley     char       *strname;
4803d0812dedSMatthew G. Knepley     char        tmpdir[PETSC_MAX_PATH_LEN];
4804d0812dedSMatthew G. Knepley     char        tmpfilename[PETSC_MAX_PATH_LEN];
4805d0812dedSMatthew G. Knepley     char        name[PETSC_MAX_PATH_LEN];
4806d0812dedSMatthew G. Knepley     MPI_Comm    comm;
4807d0812dedSMatthew G. Knepley     PetscMPIInt rank;
4808d0812dedSMatthew G. Knepley 
4809d0812dedSMatthew G. Knepley     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4810d0812dedSMatthew G. Knepley     PetscCallMPI(MPI_Comm_rank(comm, &rank));
4811d0812dedSMatthew G. Knepley     PetscCall(PetscStrchr(filename, ':', &strname));
4812d0812dedSMatthew G. Knepley     PetscCheck(strname, comm, PETSC_ERR_ARG_WRONG, "File contents must have the form \"ext:string_name\", not %s", filename);
4813d0812dedSMatthew G. Knepley     strname[0] = '\0';
4814d0812dedSMatthew G. Knepley     ++strname;
4815d0812dedSMatthew G. Knepley     PetscCall(PetscDLSym(NULL, strname, (void **)&contents));
4816d0812dedSMatthew G. Knepley     PetscCheck(contents, comm, PETSC_ERR_ARG_WRONG, "Could not locate mesh string %s", strname);
4817d0812dedSMatthew G. Knepley     PetscCall(PetscGetTmp(comm, tmpdir, PETSC_MAX_PATH_LEN));
4818ed32af8cSMatthew G. Knepley     PetscCall(PetscStrlcat(tmpdir, "/meshXXXXXX", PETSC_MAX_PATH_LEN));
4819ed32af8cSMatthew G. Knepley     PetscCall(PetscMkdtemp(tmpdir));
4820ed32af8cSMatthew G. Knepley     PetscCall(PetscSNPrintf(tmpfilename, PETSC_MAX_PATH_LEN, "%s/mesh.%s", tmpdir, filename));
4821d0812dedSMatthew G. Knepley     PetscCall(PetscViewerASCIIOpen(comm, tmpfilename, &viewer));
4822d0812dedSMatthew G. Knepley     PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", contents));
4823d0812dedSMatthew G. Knepley     PetscCall(PetscViewerDestroy(&viewer));
4824d0812dedSMatthew G. Knepley     PetscCall(DMPlexCreateFromFile(PetscObjectComm((PetscObject)dm), tmpfilename, plexname, interpolate, &dmnew));
4825ed32af8cSMatthew G. Knepley     PetscCall(PetscRMTree(tmpdir));
4826d0812dedSMatthew G. Knepley     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN, "%s Mesh", strname));
4827d0812dedSMatthew G. Knepley     PetscCall(PetscObjectSetName((PetscObject)dm, name));
4828d0812dedSMatthew G. Knepley     PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
4829d0812dedSMatthew G. Knepley     PetscCall(DMPlexReplace_Internal(dm, &dmnew));
48309318fe57SMatthew G. Knepley   } else {
48319566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)dm, DMPlexShapes[shape]));
48329318fe57SMatthew G. Knepley     switch (shape) {
4833669647acSMatthew G. Knepley     case DM_SHAPE_BOX:
48345dca41c3SJed Brown     case DM_SHAPE_ZBOX:
4835669647acSMatthew G. Knepley     case DM_SHAPE_ANNULUS: {
48369318fe57SMatthew G. Knepley       PetscInt       faces[3]  = {0, 0, 0};
48379318fe57SMatthew G. Knepley       PetscReal      lower[3]  = {0, 0, 0};
48389318fe57SMatthew G. Knepley       PetscReal      upper[3]  = {1, 1, 1};
48399318fe57SMatthew G. Knepley       DMBoundaryType bdt[3]    = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4840669647acSMatthew G. Knepley       PetscBool      isAnnular = shape == DM_SHAPE_ANNULUS ? PETSC_TRUE : PETSC_FALSE;
48419318fe57SMatthew G. Knepley       PetscInt       i, n;
48429318fe57SMatthew G. Knepley 
48439318fe57SMatthew G. Knepley       n = dim;
48449318fe57SMatthew G. Knepley       for (i = 0; i < dim; ++i) faces[i] = (dim == 1 ? 1 : 4 - dim);
48459566063dSJacob Faibussowitsch       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
48469318fe57SMatthew G. Knepley       n = 3;
48479566063dSJacob Faibussowitsch       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
484863a3b9bcSJacob Faibussowitsch       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
48499318fe57SMatthew G. Knepley       n = 3;
48509566063dSJacob Faibussowitsch       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
485163a3b9bcSJacob Faibussowitsch       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
48529318fe57SMatthew G. Knepley       n = 3;
48539566063dSJacob Faibussowitsch       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
485463a3b9bcSJacob Faibussowitsch       PetscCheck(!flg || !(n != dim), comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4855669647acSMatthew G. Knepley 
4856669647acSMatthew G. Knepley       PetscCheck(!isAnnular || dim == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Only two dimensional annuli have been implemented");
4857669647acSMatthew G. Knepley       if (isAnnular)
4858669647acSMatthew G. Knepley         for (i = 0; i < dim - 1; ++i) bdt[i] = DM_BOUNDARY_PERIODIC;
4859669647acSMatthew G. Knepley 
48609318fe57SMatthew G. Knepley       switch (cell) {
486161a622f3SMatthew G. Knepley       case DM_POLYTOPE_TRI_PRISM_TENSOR:
48629566063dSJacob Faibussowitsch         PetscCall(DMPlexCreateWedgeBoxMesh_Internal(dm, faces, lower, upper, bdt));
4863d410b0cfSMatthew G. Knepley         if (!interpolate) {
4864d410b0cfSMatthew G. Knepley           DM udm;
4865d410b0cfSMatthew G. Knepley 
48669566063dSJacob Faibussowitsch           PetscCall(DMPlexUninterpolate(dm, &udm));
486769d8a87bSksagiyam           PetscCall(DMPlexReplace_Internal(dm, &udm));
4868d410b0cfSMatthew G. Knepley         }
48699318fe57SMatthew G. Knepley         break;
4870d71ae5a4SJacob Faibussowitsch       default:
48715dca41c3SJed Brown         PetscCall(DMPlexCreateBoxMesh_Internal(dm, shape, dim, simplex, faces, lower, upper, bdt, interpolate));
4872d71ae5a4SJacob Faibussowitsch         break;
48739318fe57SMatthew G. Knepley       }
4874669647acSMatthew G. Knepley       if (isAnnular) {
4875669647acSMatthew G. Knepley         DM          cdm;
4876669647acSMatthew G. Knepley         PetscDS     cds;
4877669647acSMatthew G. Knepley         PetscScalar bounds[2] = {lower[0], upper[0]};
4878669647acSMatthew G. Knepley 
4879669647acSMatthew G. Knepley         // Fix coordinates for annular region
4880669647acSMatthew G. Knepley         PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
4881669647acSMatthew G. Knepley         PetscCall(DMSetCellCoordinatesLocal(dm, NULL));
4882669647acSMatthew G. Knepley         PetscCall(DMSetCellCoordinates(dm, NULL));
4883e65c294aSksagiyam         PetscCall(DMPlexCreateCoordinateSpace(dm, 1, PETSC_FALSE, PETSC_TRUE));
4884669647acSMatthew G. Knepley         PetscCall(DMGetCoordinateDM(dm, &cdm));
4885669647acSMatthew G. Knepley         PetscCall(DMGetDS(cdm, &cds));
4886669647acSMatthew G. Knepley         PetscCall(PetscDSSetConstants(cds, 2, bounds));
4887669647acSMatthew G. Knepley         PetscCall(DMPlexRemapGeometry(dm, 0.0, boxToAnnulus));
4888669647acSMatthew G. Knepley       }
48899371c9d4SSatish Balay     } break;
48909371c9d4SSatish Balay     case DM_SHAPE_BOX_SURFACE: {
48919318fe57SMatthew G. Knepley       PetscInt  faces[3] = {0, 0, 0};
48929318fe57SMatthew G. Knepley       PetscReal lower[3] = {0, 0, 0};
48939318fe57SMatthew G. Knepley       PetscReal upper[3] = {1, 1, 1};
48949318fe57SMatthew G. Knepley       PetscInt  i, n;
48959318fe57SMatthew G. Knepley 
48969318fe57SMatthew G. Knepley       n = dim + 1;
48979318fe57SMatthew G. Knepley       for (i = 0; i < dim + 1; ++i) faces[i] = (dim + 1 == 1 ? 1 : 4 - (dim + 1));
48989566063dSJacob Faibussowitsch       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", faces, &n, &flg));
48999318fe57SMatthew G. Knepley       n = 3;
49009566063dSJacob Faibussowitsch       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
490163a3b9bcSJacob Faibussowitsch       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
49029318fe57SMatthew G. Knepley       n = 3;
49039566063dSJacob Faibussowitsch       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
490463a3b9bcSJacob Faibussowitsch       PetscCheck(!flg || !(n != dim + 1), comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim + 1);
49059566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateBoxSurfaceMesh_Internal(dm, dim + 1, faces, lower, upper, interpolate));
49069371c9d4SSatish Balay     } break;
49079371c9d4SSatish Balay     case DM_SHAPE_SPHERE: {
49089318fe57SMatthew G. Knepley       PetscReal R = 1.0;
49099318fe57SMatthew G. Knepley 
49109566063dSJacob Faibussowitsch       PetscCall(PetscOptionsReal("-dm_plex_sphere_radius", "Radius of the sphere", "", R, &R, &flg));
49119566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateSphereMesh_Internal(dm, dim, simplex, R));
49129371c9d4SSatish Balay     } break;
49139371c9d4SSatish Balay     case DM_SHAPE_BALL: {
49149318fe57SMatthew G. Knepley       PetscReal R = 1.0;
49159318fe57SMatthew G. Knepley 
49169566063dSJacob Faibussowitsch       PetscCall(PetscOptionsReal("-dm_plex_ball_radius", "Radius of the ball", "", R, &R, &flg));
49179566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateBallMesh_Internal(dm, dim, R));
49189371c9d4SSatish Balay     } break;
49199371c9d4SSatish Balay     case DM_SHAPE_CYLINDER: {
49209318fe57SMatthew G. Knepley       DMBoundaryType bdt = DM_BOUNDARY_NONE;
49219318fe57SMatthew G. Knepley       PetscInt       Nw  = 6;
492249704ca5SMatthew G. Knepley       PetscInt       Nr  = 0;
49239318fe57SMatthew G. Knepley 
49249566063dSJacob Faibussowitsch       PetscCall(PetscOptionsEnum("-dm_plex_cylinder_bd", "Boundary type in the z direction", "", DMBoundaryTypes, (PetscEnum)bdt, (PetscEnum *)&bdt, NULL));
49259566063dSJacob Faibussowitsch       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_wedges", "Number of wedges around the cylinder", "", Nw, &Nw, NULL));
492649704ca5SMatthew G. Knepley       PetscCall(PetscOptionsInt("-dm_plex_cylinder_num_refine", "Number of refinements before projection", "", Nr, &Nr, NULL));
49279318fe57SMatthew G. Knepley       switch (cell) {
4928d71ae5a4SJacob Faibussowitsch       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4929d71ae5a4SJacob Faibussowitsch         PetscCall(DMPlexCreateWedgeCylinderMesh_Internal(dm, Nw, interpolate));
4930d71ae5a4SJacob Faibussowitsch         break;
4931d71ae5a4SJacob Faibussowitsch       default:
493249704ca5SMatthew G. Knepley         PetscCall(DMPlexCreateHexCylinderMesh_Internal(dm, bdt, Nr));
4933d71ae5a4SJacob Faibussowitsch         break;
49349318fe57SMatthew G. Knepley       }
49359371c9d4SSatish Balay     } break;
4936b7f5c055SJed Brown     case DM_SHAPE_SCHWARZ_P: // fallthrough
49379371c9d4SSatish Balay     case DM_SHAPE_GYROID: {
4938b7f5c055SJed Brown       PetscInt       extent[3] = {1, 1, 1}, refine = 0, layers = 0, three;
4939b7f5c055SJed Brown       PetscReal      thickness   = 0.;
4940b7f5c055SJed Brown       DMBoundaryType periodic[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
4941b7f5c055SJed Brown       DMPlexTPSType  tps_type    = shape == DM_SHAPE_SCHWARZ_P ? DMPLEX_TPS_SCHWARZ_P : DMPLEX_TPS_GYROID;
49421436d7faSJed Brown       PetscBool      tps_distribute;
49439566063dSJacob Faibussowitsch       PetscCall(PetscOptionsIntArray("-dm_plex_tps_extent", "Number of replicas for each of three dimensions", NULL, extent, (three = 3, &three), NULL));
49449566063dSJacob Faibussowitsch       PetscCall(PetscOptionsInt("-dm_plex_tps_refine", "Number of refinements", NULL, refine, &refine, NULL));
49459566063dSJacob Faibussowitsch       PetscCall(PetscOptionsEnumArray("-dm_plex_tps_periodic", "Periodicity in each of three dimensions", NULL, DMBoundaryTypes, (PetscEnum *)periodic, (three = 3, &three), NULL));
49469566063dSJacob Faibussowitsch       PetscCall(PetscOptionsInt("-dm_plex_tps_layers", "Number of layers in volumetric extrusion (or zero to not extrude)", NULL, layers, &layers, NULL));
49479566063dSJacob Faibussowitsch       PetscCall(PetscOptionsReal("-dm_plex_tps_thickness", "Thickness of volumetric extrusion", NULL, thickness, &thickness, NULL));
49489566063dSJacob Faibussowitsch       PetscCall(DMPlexDistributeGetDefault(dm, &tps_distribute));
49499566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_tps_distribute", "Distribute the 2D mesh prior to refinement and extrusion", NULL, tps_distribute, &tps_distribute, NULL));
49509566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateTPSMesh_Internal(dm, tps_type, extent, periodic, tps_distribute, refine, layers, thickness));
49519371c9d4SSatish Balay     } break;
49529371c9d4SSatish Balay     case DM_SHAPE_DOUBLET: {
495305bd46c0SStefano Zampini       DM        dmnew;
495405bd46c0SStefano Zampini       PetscReal rl = 0.0;
495505bd46c0SStefano Zampini 
495605bd46c0SStefano Zampini       PetscCall(PetscOptionsReal("-dm_plex_doublet_refinementlimit", "Refinement limit", NULL, rl, &rl, NULL));
495705bd46c0SStefano Zampini       PetscCall(DMPlexCreateDoublet(PetscObjectComm((PetscObject)dm), dim, simplex, interpolate, rl, &dmnew));
49585de52c6dSVaclav Hapla       PetscCall(DMPlexCopy_Internal(dm, PETSC_FALSE, PETSC_FALSE, dmnew));
495969d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &dmnew));
49609371c9d4SSatish Balay     } break;
4961cfb853baSMatthew G. Knepley     case DM_SHAPE_HYPERCUBIC: {
49628d2ec52aSSatish Balay       PetscInt       *edges, overlap = 1;
4963cfb853baSMatthew G. Knepley       PetscReal      *lower, *upper;
4964cfb853baSMatthew G. Knepley       DMBoundaryType *bdt;
4965cfb853baSMatthew G. Knepley       PetscInt        n, d;
4966cfb853baSMatthew G. Knepley 
4967cfb853baSMatthew G. Knepley       *useCoordSpace = PETSC_FALSE;
4968cfb853baSMatthew G. Knepley       PetscCall(PetscMalloc4(dim, &edges, dim, &lower, dim, &upper, dim, &bdt));
4969cfb853baSMatthew G. Knepley       for (d = 0; d < dim; ++d) {
4970cfb853baSMatthew G. Knepley         edges[d] = 1;
4971cfb853baSMatthew G. Knepley         lower[d] = 0.;
4972cfb853baSMatthew G. Knepley         upper[d] = 1.;
4973cfb853baSMatthew G. Knepley         bdt[d]   = DM_BOUNDARY_PERIODIC;
4974cfb853baSMatthew G. Knepley       }
4975cfb853baSMatthew G. Knepley       n = dim;
4976cfb853baSMatthew G. Knepley       PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", edges, &n, &flg));
4977cfb853baSMatthew G. Knepley       n = dim;
4978cfb853baSMatthew G. Knepley       PetscCall(PetscOptionsRealArray("-dm_plex_box_lower", "Lower left corner of box", "", lower, &n, &flg));
4979cfb853baSMatthew G. Knepley       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Lower box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4980cfb853baSMatthew G. Knepley       n = dim;
4981cfb853baSMatthew G. Knepley       PetscCall(PetscOptionsRealArray("-dm_plex_box_upper", "Upper right corner of box", "", upper, &n, &flg));
4982cfb853baSMatthew G. Knepley       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Upper box point had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
4983cfb853baSMatthew G. Knepley       n = dim;
4984cfb853baSMatthew G. Knepley       PetscCall(PetscOptionsEnumArray("-dm_plex_box_bd", "Boundary type for each dimension", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
4985cfb853baSMatthew G. Knepley       PetscCheck(!flg || n == dim, comm, PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
49868d2ec52aSSatish Balay       PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", overlap, &overlap, NULL, 0));
49878d2ec52aSSatish Balay       PetscCall(DMPlexCreateHypercubicMesh_Internal(dm, dim, lower, upper, edges, overlap, bdt));
4988cfb853baSMatthew G. Knepley       PetscCall(PetscFree4(edges, lower, upper, bdt));
4989cfb853baSMatthew G. Knepley     } break;
4990d71ae5a4SJacob Faibussowitsch     default:
4991d71ae5a4SJacob Faibussowitsch       SETERRQ(comm, PETSC_ERR_SUP, "Domain shape %s is unsupported", DMPlexShapes[shape]);
49929318fe57SMatthew G. Knepley     }
49939318fe57SMatthew G. Knepley   }
49949566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
499548a46eb9SPierre Jolivet   if (!((PetscObject)dm)->name && nameflg) PetscCall(PetscObjectSetName((PetscObject)dm, plexname));
4996b9da1bb3SMatthew G. Knepley   if (orient) PetscCall(DMPlexOrient(dm));
49974e22dd4cSMatthew G. Knepley   // Allow label creation
49984e22dd4cSMatthew G. Knepley   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_label_", &option, NULL, &flg));
49994e22dd4cSMatthew G. Knepley   if (flg) {
50004e22dd4cSMatthew G. Knepley     DMLabel     label;
5001db1ec57dSMatthew G. Knepley     PetscInt   *points, cStart, cEnd, n;
50024e22dd4cSMatthew G. Knepley     char        fulloption[PETSC_MAX_PATH_LEN];
50034e22dd4cSMatthew G. Knepley     const char *name = &option[14];
50044e22dd4cSMatthew G. Knepley 
5005db1ec57dSMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5006db1ec57dSMatthew G. Knepley     n = PetscMax(cEnd - cStart, 1024);
5007db1ec57dSMatthew G. Knepley     PetscCall(PetscMalloc1(n, &points));
50084e22dd4cSMatthew G. Knepley     PetscCall(DMCreateLabel(dm, name));
50094e22dd4cSMatthew G. Knepley     PetscCall(DMGetLabel(dm, name, &label));
50104e22dd4cSMatthew G. Knepley     fulloption[0] = '-';
50114e22dd4cSMatthew G. Knepley     fulloption[1] = 0;
50124e22dd4cSMatthew G. Knepley     PetscCall(PetscStrlcat(fulloption, option, PETSC_MAX_PATH_LEN));
50134e22dd4cSMatthew G. Knepley     PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, NULL));
50144e22dd4cSMatthew G. Knepley     for (PetscInt p = 0; p < n; ++p) PetscCall(DMLabelSetValue(label, points[p], 1));
5015db1ec57dSMatthew G. Knepley     PetscCall(PetscFree(points));
50164e22dd4cSMatthew G. Knepley   }
5017dd0eeac9SMatthew G. Knepley   // Allow cohesive label creation
5018dd0eeac9SMatthew G. Knepley   //   Faces are input, completed, and all points are marked with their depth
5019dd0eeac9SMatthew G. Knepley   PetscCall(PetscOptionsFindPairPrefix_Private(NULL, ((PetscObject)dm)->prefix, "-dm_plex_cohesive_label_", &option, NULL, &flg));
5020dd0eeac9SMatthew G. Knepley   if (flg) {
5021dd0eeac9SMatthew G. Knepley     DMLabel   label;
5022dd0eeac9SMatthew G. Knepley     PetscInt  points[1024], n, pStart, pEnd, Nl = 1;
50235390be7dSMatthew G. Knepley     PetscBool noCreate = PETSC_FALSE;
5024dd0eeac9SMatthew G. Knepley     char      fulloption[PETSC_MAX_PATH_LEN];
5025dd0eeac9SMatthew G. Knepley     char      name[PETSC_MAX_PATH_LEN];
5026dd0eeac9SMatthew G. Knepley     size_t    len;
5027dd0eeac9SMatthew G. Knepley 
5028dd0eeac9SMatthew G. Knepley     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
5029dd0eeac9SMatthew G. Knepley     PetscCall(PetscStrncpy(name, &option[23], PETSC_MAX_PATH_LEN));
5030dd0eeac9SMatthew G. Knepley     PetscCall(PetscStrlen(name, &len));
5031dd0eeac9SMatthew G. Knepley     if (name[len - 1] == '0') Nl = 10;
5032dd0eeac9SMatthew G. Knepley     for (PetscInt l = 0; l < Nl; ++l) {
50336497c311SBarry Smith       if (l > 0) name[len - 1] = (char)('0' + l);
5034dd0eeac9SMatthew G. Knepley       fulloption[0] = 0;
5035dd0eeac9SMatthew G. Knepley       PetscCall(PetscStrlcat(fulloption, "-dm_plex_cohesive_label_", 32));
5036dd0eeac9SMatthew G. Knepley       PetscCall(PetscStrlcat(fulloption, name, PETSC_MAX_PATH_LEN - 32));
5037dd0eeac9SMatthew G. Knepley       n = 1024;
5038dd0eeac9SMatthew G. Knepley       PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)dm)->prefix, fulloption, points, &n, &flg));
5039dd0eeac9SMatthew G. Knepley       if (!flg) break;
50405390be7dSMatthew G. Knepley       PetscCall(DMHasLabel(dm, name, &noCreate));
50415390be7dSMatthew G. Knepley       if (noCreate) {
50425390be7dSMatthew G. Knepley         DMLabel         inlabel;
50435390be7dSMatthew G. Knepley         IS              pointIS;
50445390be7dSMatthew G. Knepley         const PetscInt *lpoints;
50455390be7dSMatthew G. Knepley         PetscInt        pdep, ln, inval = points[0];
50465390be7dSMatthew G. Knepley         char            newname[PETSC_MAX_PATH_LEN];
50475390be7dSMatthew G. Knepley 
50485390be7dSMatthew G. Knepley         PetscCheck(n == 1, comm, PETSC_ERR_ARG_WRONG, "Must specify a label value with this option");
50495390be7dSMatthew G. Knepley         PetscCall(DMGetLabel(dm, name, &inlabel));
50505390be7dSMatthew G. Knepley         PetscCall(DMLabelGetStratumIS(inlabel, inval, &pointIS));
50515390be7dSMatthew G. Knepley         PetscCall(ISGetLocalSize(pointIS, &ln));
50525390be7dSMatthew G. Knepley         PetscCall(ISGetIndices(pointIS, &lpoints));
50535390be7dSMatthew G. Knepley         PetscCall(DMPlexGetPointDepth(dm, lpoints[0], &pdep));
50545390be7dSMatthew G. Knepley         PetscCall(PetscSNPrintf(newname, PETSC_MAX_PATH_LEN, "%s%" PetscInt_FMT, name, points[0]));
50555390be7dSMatthew G. Knepley         PetscCall(DMCreateLabel(dm, newname));
50565390be7dSMatthew G. Knepley         PetscCall(DMGetLabel(dm, newname, &label));
50575390be7dSMatthew G. Knepley         if (!pdep) PetscCall(ProcessCohesiveLabel_Vertices(dm, label, inlabel, inval, ln, lpoints));
50585390be7dSMatthew G. Knepley         else PetscCall(ProcessCohesiveLabel_Faces(dm, label, ln, lpoints));
50595390be7dSMatthew G. Knepley         PetscCall(ISRestoreIndices(pointIS, &lpoints));
50605390be7dSMatthew G. Knepley         PetscCall(ISDestroy(&pointIS));
50615390be7dSMatthew G. Knepley       } else {
5062dd0eeac9SMatthew G. Knepley         PetscCall(DMCreateLabel(dm, name));
5063dd0eeac9SMatthew G. Knepley         PetscCall(DMGetLabel(dm, name, &label));
5064dd0eeac9SMatthew G. Knepley         if (pStart >= pEnd) n = 0;
50655390be7dSMatthew G. Knepley         PetscCall(ProcessCohesiveLabel_Faces(dm, label, n, points));
5066dd0eeac9SMatthew G. Knepley       }
5067dd0eeac9SMatthew G. Knepley       PetscCall(DMPlexOrientLabel(dm, label));
50680542aa8cSMatthew G. Knepley       PetscCall(DMPlexLabelCohesiveComplete(dm, label, NULL, 1, PETSC_FALSE, PETSC_FALSE, NULL));
5069dd0eeac9SMatthew G. Knepley     }
5070dd0eeac9SMatthew G. Knepley   }
50715390be7dSMatthew G. Knepley   PetscCall(DMViewFromOptions(dm, NULL, "-created_dm_view"));
5072708be2fdSJed Brown   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromOptions, dm, 0, 0, 0));
50733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50740a6ba040SMatthew G. Knepley }
50750a6ba040SMatthew G. Knepley 
5076ce78bad3SBarry Smith PetscErrorCode DMSetFromOptions_NonRefinement_Plex(DM dm, PetscOptionItems PetscOptionsObject)
5077d71ae5a4SJacob Faibussowitsch {
50780a6ba040SMatthew G. Knepley   DM_Plex  *mesh = (DM_Plex *)dm->data;
50797f9d8d6cSVaclav Hapla   PetscBool flg, flg2;
50809318fe57SMatthew G. Knepley   char      bdLabel[PETSC_MAX_PATH_LEN];
5081adc21957SMatthew G. Knepley   char      method[PETSC_MAX_PATH_LEN];
50820a6ba040SMatthew G. Knepley 
50830a6ba040SMatthew G. Knepley   PetscFunctionBegin;
50840a6ba040SMatthew G. Knepley   /* Handle viewing */
50859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_print_set_values", "Output all set values info", "DMPlexMatSetClosure", PETSC_FALSE, &mesh->printSetValues, NULL));
50865962854dSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fem", "Debug output level for all fem computations", "DMPlexSNESComputeResidualFEM", 0, &mesh->printFEM, NULL, 0));
50875962854dSMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_fvm", "Debug output level for all fvm computations", "DMPlexSNESComputeResidualFVM", 0, &mesh->printFVM, NULL, 0));
50889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-dm_plex_print_tol", "Tolerance for FEM output", "DMPlexSNESComputeResidualFEM", mesh->printTol, &mesh->printTol, NULL));
50899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_l2", "Debug output level all L2 diff computations", "DMComputeL2Diff", 0, &mesh->printL2, NULL, 0));
5090f5867de0SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_locate", "Debug output level all point location computations", "DMLocatePoints", 0, &mesh->printLocate, NULL, 0));
5091a77a5016SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_plex_print_project", "Debug output level all projection computations", "DMPlexProject", 0, &mesh->printProject, NULL, 0));
50929566063dSJacob Faibussowitsch   PetscCall(DMMonitorSetFromOptions(dm, "-dm_plex_monitor_throughput", "Monitor the simulation throughput", "DMPlexMonitorThroughput", DMPlexMonitorThroughput, NULL, &flg));
50939566063dSJacob Faibussowitsch   if (flg) PetscCall(PetscLogDefaultBegin());
50945e2c5519SMatthew G. Knepley   // Interpolation
50955e2c5519SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_interpolate_prefer_tensor", "When different orderings exist, prefer the tensor order", "DMPlexSetInterpolationPreferTensor", mesh->interpolatePreferTensor, &mesh->interpolatePreferTensor, NULL));
50969318fe57SMatthew G. Knepley   /* Labeling */
50970b595cf8SStefano Zampini   PetscCall(PetscOptionsString("-dm_plex_boundary_label", "Label to mark the mesh boundary", "", NULL, bdLabel, sizeof(bdLabel), &flg));
50989566063dSJacob Faibussowitsch   if (flg) PetscCall(DMPlexCreateBoundaryLabel_Private(dm, bdLabel));
5099953fc75cSMatthew G. Knepley   /* Point Location */
51009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_hash_location", "Use grid hashing for point location", "DMInterpolate", PETSC_FALSE, &mesh->useHashLocation, NULL));
51010848f4b5SMatthew G. Knepley   /* Partitioning and distribution */
51029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", PETSC_FALSE, &mesh->partitionBalance, NULL));
5103d02c7345SMatthew G. Knepley   /* Reordering */
5104adc21957SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_reorder_section", "Compute point permutation for local section", "DMReorderSectionSetDefault", PETSC_FALSE, &flg2, &flg));
5105adc21957SMatthew G. Knepley   if (flg) PetscCall(DMReorderSectionSetDefault(dm, flg2 ? DM_REORDER_DEFAULT_TRUE : DM_REORDER_DEFAULT_FALSE));
51060b595cf8SStefano Zampini   PetscCall(PetscOptionsString("-dm_reorder_section_type", "Reordering method for local section", "DMReorderSectionSetType", NULL, method, PETSC_MAX_PATH_LEN, &flg));
5107adc21957SMatthew G. Knepley   if (flg) PetscCall(DMReorderSectionSetType(dm, method));
51082e62ab5aSMatthew G. Knepley   /* Generation and remeshing */
51099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_remesh_bd", "Allow changes to the boundary on remeshing", "DMAdapt", PETSC_FALSE, &mesh->remeshBd, NULL));
511061f058f9SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_save_transform", "Save the transform producing this mesh", "DMAdapt", PETSC_FALSE, &mesh->saveTransform, NULL));
5111b29cfa1cSToby Isaac   /* Projection behavior */
5112d5b43468SJose E. Roman   PetscCall(PetscOptionsBoundedInt("-dm_plex_max_projection_height", "Maximum mesh point height used to project locally", "DMPlexSetMaxProjectionHeight", 0, &mesh->maxProjectionHeight, NULL, 0));
51139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_regular_refinement", "Use special nested projection algorithm for regular refinement", "DMPlexSetRegularRefinement", mesh->regularRefinement, &mesh->regularRefinement, NULL));
5114f12cf164SMatthew G. Knepley   /* Checking structure */
5115f12cf164SMatthew G. Knepley   {
51167f9d8d6cSVaclav Hapla     PetscBool all = PETSC_FALSE;
5117f12cf164SMatthew G. Knepley 
51187f9d8d6cSVaclav Hapla     PetscCall(PetscOptionsBool("-dm_plex_check_all", "Perform all basic checks", "DMPlexCheck", PETSC_FALSE, &all, NULL));
51197f9d8d6cSVaclav Hapla     if (all) {
51207f9d8d6cSVaclav Hapla       PetscCall(DMPlexCheck(dm));
51217f9d8d6cSVaclav Hapla     } else {
51229566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_symmetry", "Check that the adjacency information in the mesh is symmetric", "DMPlexCheckSymmetry", PETSC_FALSE, &flg, &flg2));
51237f9d8d6cSVaclav Hapla       if (flg && flg2) PetscCall(DMPlexCheckSymmetry(dm));
51249566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_skeleton", "Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes)", "DMPlexCheckSkeleton", PETSC_FALSE, &flg, &flg2));
51257f9d8d6cSVaclav Hapla       if (flg && flg2) PetscCall(DMPlexCheckSkeleton(dm, 0));
51269566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_faces", "Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type", "DMPlexCheckFaces", PETSC_FALSE, &flg, &flg2));
51277f9d8d6cSVaclav Hapla       if (flg && flg2) PetscCall(DMPlexCheckFaces(dm, 0));
51289566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_geometry", "Check that cells have positive volume", "DMPlexCheckGeometry", PETSC_FALSE, &flg, &flg2));
51297f9d8d6cSVaclav Hapla       if (flg && flg2) PetscCall(DMPlexCheckGeometry(dm));
51309566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_pointsf", "Check some necessary conditions for PointSF", "DMPlexCheckPointSF", PETSC_FALSE, &flg, &flg2));
5131d7d32a9aSMatthew G. Knepley       if (flg && flg2) PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE));
51329566063dSJacob Faibussowitsch       PetscCall(PetscOptionsBool("-dm_plex_check_interface_cones", "Check points on inter-partition interfaces have conforming order of cone points", "DMPlexCheckInterfaceCones", PETSC_FALSE, &flg, &flg2));
51337f9d8d6cSVaclav Hapla       if (flg && flg2) PetscCall(DMPlexCheckInterfaceCones(dm));
51347f9d8d6cSVaclav Hapla     }
51359566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-dm_plex_check_cell_shape", "Check cell shape", "DMPlexCheckCellShape", PETSC_FALSE, &flg, &flg2));
51369566063dSJacob Faibussowitsch     if (flg && flg2) PetscCall(DMPlexCheckCellShape(dm, PETSC_TRUE, PETSC_DETERMINE));
5137f12cf164SMatthew G. Knepley   }
51389318fe57SMatthew G. Knepley   {
51399318fe57SMatthew G. Knepley     PetscReal scale = 1.0;
51404f3833eaSMatthew G. Knepley 
51419566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-dm_plex_scale", "Scale factor for mesh coordinates", "DMPlexScale", scale, &scale, &flg));
51429318fe57SMatthew G. Knepley     if (flg) {
51439318fe57SMatthew G. Knepley       Vec coordinates, coordinatesLocal;
51449318fe57SMatthew G. Knepley 
51459566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(dm, &coordinates));
51469566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(dm, &coordinatesLocal));
51479566063dSJacob Faibussowitsch       PetscCall(VecScale(coordinates, scale));
51489566063dSJacob Faibussowitsch       PetscCall(VecScale(coordinatesLocal, scale));
51499318fe57SMatthew G. Knepley     }
51509318fe57SMatthew G. Knepley   }
51519566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerSetFromOptions(mesh->partitioner));
51523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
515368d4fef7SMatthew G. Knepley }
515468d4fef7SMatthew G. Knepley 
5155ce78bad3SBarry Smith PetscErrorCode DMSetFromOptions_Overlap_Plex(DM dm, PetscOptionItems PetscOptionsObject, PetscInt *overlap)
5156d71ae5a4SJacob Faibussowitsch {
5157c506a872SMatthew G. Knepley   PetscInt  numOvLabels = 16, numOvExLabels = 16;
5158c506a872SMatthew G. Knepley   char     *ovLabelNames[16], *ovExLabelNames[16];
5159c506a872SMatthew G. Knepley   PetscInt  numOvValues = 16, numOvExValues = 16, l;
5160c506a872SMatthew G. Knepley   PetscBool flg;
5161c506a872SMatthew G. Knepley 
5162c506a872SMatthew G. Knepley   PetscFunctionBegin;
5163c506a872SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_distribute_overlap", "The size of the overlap halo", "DMPlexDistribute", *overlap, overlap, NULL, 0));
5164c506a872SMatthew G. Knepley   PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_labels", "List of overlap label names", "DMPlexDistribute", ovLabelNames, &numOvLabels, &flg));
5165c506a872SMatthew G. Knepley   if (!flg) numOvLabels = 0;
5166c506a872SMatthew G. Knepley   if (numOvLabels) {
5167c506a872SMatthew G. Knepley     ((DM_Plex *)dm->data)->numOvLabels = numOvLabels;
5168c506a872SMatthew G. Knepley     for (l = 0; l < numOvLabels; ++l) {
5169c506a872SMatthew G. Knepley       PetscCall(DMGetLabel(dm, ovLabelNames[l], &((DM_Plex *)dm->data)->ovLabels[l]));
5170c506a872SMatthew G. Knepley       PetscCheck(((DM_Plex *)dm->data)->ovLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovLabelNames[l]);
5171c506a872SMatthew G. Knepley       PetscCall(PetscFree(ovLabelNames[l]));
5172c506a872SMatthew G. Knepley     }
5173c506a872SMatthew G. Knepley     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_values", "List of overlap label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovValues, &numOvValues, &flg));
5174c506a872SMatthew G. Knepley     if (!flg) numOvValues = 0;
5175c506a872SMatthew G. Knepley     PetscCheck(numOvLabels == numOvValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvLabels, numOvValues);
5176c506a872SMatthew G. Knepley 
5177c506a872SMatthew G. Knepley     PetscCall(PetscOptionsStringArray("-dm_distribute_overlap_exclude_labels", "List of overlap exclude label names", "DMPlexDistribute", ovExLabelNames, &numOvExLabels, &flg));
5178c506a872SMatthew G. Knepley     if (!flg) numOvExLabels = 0;
5179c506a872SMatthew G. Knepley     ((DM_Plex *)dm->data)->numOvExLabels = numOvExLabels;
5180c506a872SMatthew G. Knepley     for (l = 0; l < numOvExLabels; ++l) {
5181c506a872SMatthew G. Knepley       PetscCall(DMGetLabel(dm, ovExLabelNames[l], &((DM_Plex *)dm->data)->ovExLabels[l]));
5182c506a872SMatthew G. Knepley       PetscCheck(((DM_Plex *)dm->data)->ovExLabels[l], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid label name %s", ovExLabelNames[l]);
5183c506a872SMatthew G. Knepley       PetscCall(PetscFree(ovExLabelNames[l]));
5184c506a872SMatthew G. Knepley     }
5185c506a872SMatthew G. Knepley     PetscCall(PetscOptionsIntArray("-dm_distribute_overlap_exclude_values", "List of overlap exclude label values", "DMPlexDistribute", ((DM_Plex *)dm->data)->ovExValues, &numOvExValues, &flg));
5186c506a872SMatthew G. Knepley     if (!flg) numOvExValues = 0;
5187c506a872SMatthew G. Knepley     PetscCheck(numOvExLabels == numOvExValues, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "The number of exclude labels %" PetscInt_FMT " must match the number of values %" PetscInt_FMT, numOvExLabels, numOvExValues);
5188c506a872SMatthew G. Knepley   }
51893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5190c506a872SMatthew G. Knepley }
5191c506a872SMatthew G. Knepley 
5192ce78bad3SBarry Smith static PetscErrorCode DMSetFromOptions_Plex(DM dm, PetscOptionItems PetscOptionsObject)
5193d71ae5a4SJacob Faibussowitsch {
5194bdf63967SMatthew G. Knepley   PetscFunctionList    ordlist;
5195bdf63967SMatthew G. Knepley   char                 oname[256];
51964e22dd4cSMatthew G. Knepley   char                 sublabelname[PETSC_MAX_PATH_LEN] = "";
5197adc21957SMatthew G. Knepley   DMReorderDefaultFlag reorder;
5198d410b0cfSMatthew G. Knepley   PetscReal            volume    = -1.0;
51999318fe57SMatthew G. Knepley   PetscInt             prerefine = 0, refine = 0, r, coarsen = 0, overlap = 0, extLayers = 0, dim;
5200530e699aSMatthew G. Knepley   PetscBool            uniformOrig = PETSC_FALSE, uniform = PETSC_TRUE, distribute, saveSF = PETSC_FALSE, interpolate = PETSC_TRUE, coordSpace = PETSC_FALSE, remap = PETSC_TRUE, ghostCells = PETSC_FALSE, isHierarchy, flg;
520168d4fef7SMatthew G. Knepley 
520268d4fef7SMatthew G. Knepley   PetscFunctionBegin;
5203d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Options");
5204dd4c3f67SMatthew G. Knepley   if (dm->cloneOpts) goto non_refine;
52059318fe57SMatthew G. Knepley   /* Handle automatic creation */
52069566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
5207530e699aSMatthew G. Knepley   if (dim < 0) PetscCall(DMPlexCreateFromOptions_Internal(PetscOptionsObject, &coordSpace, dm));
52086bc1bd01Sksagiyam   PetscCall(DMGetDimension(dm, &dim));
5209d89e6e46SMatthew G. Knepley   /* Handle interpolation before distribution */
52109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_interpolate_pre", "Flag to interpolate mesh before distribution", "", interpolate, &interpolate, &flg));
5211d89e6e46SMatthew G. Knepley   if (flg) {
5212d89e6e46SMatthew G. Knepley     DMPlexInterpolatedFlag interpolated;
5213d89e6e46SMatthew G. Knepley 
52149566063dSJacob Faibussowitsch     PetscCall(DMPlexIsInterpolated(dm, &interpolated));
5215d89e6e46SMatthew G. Knepley     if (interpolated == DMPLEX_INTERPOLATED_FULL && !interpolate) {
5216d89e6e46SMatthew G. Knepley       DM udm;
5217d89e6e46SMatthew G. Knepley 
52189566063dSJacob Faibussowitsch       PetscCall(DMPlexUninterpolate(dm, &udm));
521969d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &udm));
5220d89e6e46SMatthew G. Knepley     } else if (interpolated != DMPLEX_INTERPOLATED_FULL && interpolate) {
5221d89e6e46SMatthew G. Knepley       DM idm;
5222d89e6e46SMatthew G. Knepley 
52239566063dSJacob Faibussowitsch       PetscCall(DMPlexInterpolate(dm, &idm));
522469d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &idm));
5225d89e6e46SMatthew G. Knepley     }
5226d89e6e46SMatthew G. Knepley   }
52274e22dd4cSMatthew G. Knepley   // Handle submesh selection before distribution
52284e22dd4cSMatthew G. Knepley   PetscCall(PetscOptionsString("-dm_plex_submesh", "Label to use for submesh selection", "", sublabelname, sublabelname, PETSC_MAX_PATH_LEN, &flg));
52294e22dd4cSMatthew G. Knepley   if (flg) {
52304e22dd4cSMatthew G. Knepley     DM              subdm;
52314e22dd4cSMatthew G. Knepley     DMLabel         label;
52324e22dd4cSMatthew G. Knepley     IS              valueIS, pointIS;
52334e22dd4cSMatthew G. Knepley     const PetscInt *values, *points;
52344e22dd4cSMatthew G. Knepley     PetscBool       markedFaces = PETSC_FALSE;
52354e22dd4cSMatthew G. Knepley     PetscInt        Nv, value, Np;
52364e22dd4cSMatthew G. Knepley 
52374e22dd4cSMatthew G. Knepley     PetscCall(DMGetLabel(dm, sublabelname, &label));
52384e22dd4cSMatthew G. Knepley     PetscCall(DMLabelGetNumValues(label, &Nv));
52394e22dd4cSMatthew G. Knepley     PetscCheck(Nv == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Only a single label value is currently supported for submesh selection, not %" PetscInt_FMT, Nv);
52404e22dd4cSMatthew G. Knepley     PetscCall(DMLabelGetValueIS(label, &valueIS));
52414e22dd4cSMatthew G. Knepley     PetscCall(ISGetIndices(valueIS, &values));
52424e22dd4cSMatthew G. Knepley     value = values[0];
52434e22dd4cSMatthew G. Knepley     PetscCall(ISRestoreIndices(valueIS, &values));
52444e22dd4cSMatthew G. Knepley     PetscCall(ISDestroy(&valueIS));
52454e22dd4cSMatthew G. Knepley     PetscCall(DMLabelGetStratumSize(label, value, &Np));
52464e22dd4cSMatthew G. Knepley     PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
52474e22dd4cSMatthew G. Knepley     PetscCall(ISGetIndices(pointIS, &points));
52484e22dd4cSMatthew G. Knepley     for (PetscInt p = 0; p < Np; ++p) {
52494e22dd4cSMatthew G. Knepley       PetscInt pdepth;
52504e22dd4cSMatthew G. Knepley 
52514e22dd4cSMatthew G. Knepley       PetscCall(DMPlexGetPointDepth(dm, points[p], &pdepth));
52524e22dd4cSMatthew G. Knepley       if (pdepth) {
52534e22dd4cSMatthew G. Knepley         markedFaces = PETSC_TRUE;
52544e22dd4cSMatthew G. Knepley         break;
52554e22dd4cSMatthew G. Knepley       }
52564e22dd4cSMatthew G. Knepley     }
52574e22dd4cSMatthew G. Knepley     PetscCall(ISRestoreIndices(pointIS, &points));
52584e22dd4cSMatthew G. Knepley     PetscCall(ISDestroy(&pointIS));
52594e22dd4cSMatthew G. Knepley     PetscCall(DMPlexCreateSubmesh(dm, label, value, markedFaces, &subdm));
52604e22dd4cSMatthew G. Knepley     PetscCall(DMPlexReplace_Internal(dm, &subdm));
52614e22dd4cSMatthew G. Knepley     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
52624e22dd4cSMatthew G. Knepley   }
52639b44eab4SMatthew G. Knepley   /* Handle DMPlex refinement before distribution */
52649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetRefinementUniform(dm, &uniformOrig));
52659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_refine_pre", "The number of refinements before distribution", "DMCreate", prerefine, &prerefine, NULL, 0));
52669566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_refine_remap_pre", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
52679566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_refine_uniform_pre", "Flag for uniform refinement before distribution", "DMCreate", uniform, &uniform, &flg));
52689566063dSJacob Faibussowitsch   if (flg) PetscCall(DMPlexSetRefinementUniform(dm, uniform));
52699566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-dm_refine_volume_limit_pre", "The maximum cell volume after refinement before distribution", "DMCreate", volume, &volume, &flg));
52709318fe57SMatthew G. Knepley   if (flg) {
52719566063dSJacob Faibussowitsch     PetscCall(DMPlexSetRefinementUniform(dm, PETSC_FALSE));
52729566063dSJacob Faibussowitsch     PetscCall(DMPlexSetRefinementLimit(dm, volume));
52739318fe57SMatthew G. Knepley     prerefine = PetscMax(prerefine, 1);
52749318fe57SMatthew G. Knepley   }
5275b23db253SStefano Zampini   if (prerefine) PetscCall(DMLocalizeCoordinates(dm));
52769b44eab4SMatthew G. Knepley   for (r = 0; r < prerefine; ++r) {
52779b44eab4SMatthew G. Knepley     DM            rdm;
52782192575eSBarry Smith     PetscPointFn *coordFunc;
52799b44eab4SMatthew G. Knepley 
5280509b31aaSMatthew G. Knepley     PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
5281dbbe0bcdSBarry Smith     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
52829566063dSJacob Faibussowitsch     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
528369d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &rdm));
5284dbbe0bcdSBarry Smith     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
528561a622f3SMatthew G. Knepley     if (coordFunc && remap) {
52869566063dSJacob Faibussowitsch       PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5287509b31aaSMatthew G. Knepley       PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
52889b44eab4SMatthew G. Knepley     }
52899b44eab4SMatthew G. Knepley   }
52909566063dSJacob Faibussowitsch   PetscCall(DMPlexSetRefinementUniform(dm, uniformOrig));
52919318fe57SMatthew G. Knepley   /* Handle DMPlex extrusion before distribution */
52929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_extrude", "The number of layers to extrude", "", extLayers, &extLayers, NULL, 0));
52939318fe57SMatthew G. Knepley   if (extLayers) {
52949318fe57SMatthew G. Knepley     DM edm;
52959318fe57SMatthew G. Knepley 
52969566063dSJacob Faibussowitsch     PetscCall(DMExtrude(dm, extLayers, &edm));
529769d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &edm));
5298509b31aaSMatthew G. Knepley     PetscCall(DMPlexSetCoordinateMap(dm, NULL));
5299dbbe0bcdSBarry Smith     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5300d410b0cfSMatthew G. Knepley     extLayers = 0;
53015e17fc22SAidan Hamilton     PetscCall(DMGetDimension(dm, &dim));
53029318fe57SMatthew G. Knepley   }
5303bdf63967SMatthew G. Knepley   /* Handle DMPlex reordering before distribution */
53046bc1bd01Sksagiyam   PetscCall(DMPlexReorderGetDefault(dm, &reorder));
53059566063dSJacob Faibussowitsch   PetscCall(MatGetOrderingList(&ordlist));
53066bc1bd01Sksagiyam   PetscCall(PetscStrncpy(oname, MATORDERINGNATURAL, sizeof(oname)));
53079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-dm_plex_reorder", "Set mesh reordering type", "DMPlexGetOrdering", ordlist, MATORDERINGNATURAL, oname, sizeof(oname), &flg));
5308adc21957SMatthew G. Knepley   if (reorder == DM_REORDER_DEFAULT_TRUE || flg) {
5309bdf63967SMatthew G. Knepley     DM pdm;
5310bdf63967SMatthew G. Knepley     IS perm;
5311bdf63967SMatthew G. Knepley 
53129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetOrdering(dm, oname, NULL, &perm));
53139566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dm, perm, &pdm));
53149566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&perm));
531569d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &pdm));
5316dbbe0bcdSBarry Smith     PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
5317bdf63967SMatthew G. Knepley   }
53189b44eab4SMatthew G. Knepley   /* Handle DMPlex distribution */
53199566063dSJacob Faibussowitsch   PetscCall(DMPlexDistributeGetDefault(dm, &distribute));
5320c506a872SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_distribute", "Flag to redistribute a mesh among processes", "DMPlexDistribute", distribute, &distribute, NULL));
5321a286e215SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_distribute_save_sf", "Flag to save the migration SF", "DMPlexSetMigrationSF", saveSF, &saveSF, NULL));
5322dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_Overlap_Plex(dm, PetscOptionsObject, &overlap));
53239b44eab4SMatthew G. Knepley   if (distribute) {
53249b44eab4SMatthew G. Knepley     DM               pdm = NULL;
53259b44eab4SMatthew G. Knepley     PetscPartitioner part;
5326a286e215SMatthew G. Knepley     PetscSF          sfMigration;
53279566ead2SJames Wright     PetscBool        use_partition_balance;
53289b44eab4SMatthew G. Knepley 
53299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetPartitioner(dm, &part));
53309566063dSJacob Faibussowitsch     PetscCall(PetscPartitionerSetFromOptions(part));
53319566ead2SJames Wright     PetscCall(DMPlexGetPartitionBalance(dm, &use_partition_balance));
53329566ead2SJames Wright     PetscCall(PetscOptionsBool("-dm_plex_partition_balance", "Attempt to evenly divide points on partition boundary between processes", "DMPlexSetPartitionBalance", use_partition_balance, &use_partition_balance, &flg));
53339566ead2SJames Wright     if (flg) PetscCall(DMPlexSetPartitionBalance(dm, use_partition_balance));
5334a286e215SMatthew G. Knepley     PetscCall(DMPlexDistribute(dm, overlap, &sfMigration, &pdm));
53355d2873a6SJames Wright     if (pdm) {
53365d2873a6SJames Wright       // Delete the local section to force the existing one to be rebuilt with the distributed DM
53375d2873a6SJames Wright       PetscCall(DMSetLocalSection(dm, pdm->localSection));
53385d2873a6SJames Wright       PetscCall(DMPlexReplace_Internal(dm, &pdm));
53395d2873a6SJames Wright     }
5340a286e215SMatthew G. Knepley     if (saveSF) PetscCall(DMPlexSetMigrationSF(dm, sfMigration));
5341a286e215SMatthew G. Knepley     PetscCall(PetscSFDestroy(&sfMigration));
53429b44eab4SMatthew G. Knepley   }
53434054ae39SJames Wright 
53444054ae39SJames Wright   {
53454054ae39SJames Wright     PetscBool useBoxLabel = PETSC_FALSE;
53464054ae39SJames Wright     PetscCall(PetscOptionsBool("-dm_plex_box_label", "Create 'Face Sets' assuming boundary faces align with cartesian directions", "DMCreate", useBoxLabel, &useBoxLabel, NULL));
5347d7d2d1d2SJames Wright     if (useBoxLabel) {
5348d7d2d1d2SJames Wright       PetscInt       n      = 3;
5349d7d2d1d2SJames Wright       DMBoundaryType bdt[3] = {DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE};
5350d7d2d1d2SJames Wright 
5351d7d2d1d2SJames Wright       PetscCall(PetscOptionsEnumArray("-dm_plex_box_label_bd", "Boundary type for each dimension when using -dm_plex_box_label", "", DMBoundaryTypes, (PetscEnum *)bdt, &n, &flg));
5352d7d2d1d2SJames Wright       PetscCheck(!flg || !(n != dim), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Box boundary types had %" PetscInt_FMT " values, should have been %" PetscInt_FMT, n, dim);
5353d7d2d1d2SJames Wright       PetscCall(DMPlexSetBoxLabel_Internal(dm, bdt));
5354d7d2d1d2SJames Wright     }
53554054ae39SJames Wright   }
5356d2b2dc1eSMatthew G. Knepley   /* Must check CEED options before creating function space for coordinates */
5357d2b2dc1eSMatthew G. Knepley   {
5358d2b2dc1eSMatthew G. Knepley     PetscBool useCeed = PETSC_FALSE, flg;
5359d2b2dc1eSMatthew G. Knepley 
5360d2b2dc1eSMatthew G. Knepley     PetscCall(PetscOptionsBool("-dm_plex_use_ceed", "Use LibCEED as the FEM backend", "DMPlexSetUseCeed", useCeed, &useCeed, &flg));
5361d2b2dc1eSMatthew G. Knepley     if (flg) PetscCall(DMPlexSetUseCeed(dm, useCeed));
5362d2b2dc1eSMatthew G. Knepley   }
53639318fe57SMatthew G. Knepley   /* Create coordinate space */
5364530e699aSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_coord_space", "Use an FEM space for coordinates", "", coordSpace, &coordSpace, NULL));
5365530e699aSMatthew G. Knepley   if (coordSpace) {
5366e44f6aebSMatthew G. Knepley     PetscInt  degree = 1, deg;
53675515ebd3SMatthew G. Knepley     PetscInt  height = 0;
53685515ebd3SMatthew G. Knepley     DM        cdm;
5369530e699aSMatthew G. Knepley     PetscBool localize = PETSC_TRUE, sparseLocalize = PETSC_TRUE;
53709318fe57SMatthew G. Knepley 
53719566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-dm_coord_petscspace_degree", "FEM degree for coordinate space", "", degree, &degree, NULL));
5372e44f6aebSMatthew G. Knepley     PetscCall(DMGetCoordinateDegree_Internal(dm, &deg));
5373e65c294aSksagiyam     if (coordSpace && deg <= 1) PetscCall(DMPlexCreateCoordinateSpace(dm, degree, PETSC_FALSE, PETSC_TRUE));
53745515ebd3SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
5375530e699aSMatthew G. Knepley     if (!coordSpace) {
537661a622f3SMatthew G. Knepley       PetscDS      cds;
537761a622f3SMatthew G. Knepley       PetscObject  obj;
537861a622f3SMatthew G. Knepley       PetscClassId id;
537961a622f3SMatthew G. Knepley 
53809566063dSJacob Faibussowitsch       PetscCall(DMGetDS(cdm, &cds));
53819566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
53829566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
538361a622f3SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
538461a622f3SMatthew G. Knepley         PetscContainer dummy;
538561a622f3SMatthew G. Knepley 
53869566063dSJacob Faibussowitsch         PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &dummy));
53879566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetName((PetscObject)dummy, "coordinates"));
53889566063dSJacob Faibussowitsch         PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)dummy));
53899566063dSJacob Faibussowitsch         PetscCall(PetscContainerDestroy(&dummy));
53909566063dSJacob Faibussowitsch         PetscCall(DMClearDS(cdm));
539161a622f3SMatthew G. Knepley       }
5392509b31aaSMatthew G. Knepley       PetscCall(DMPlexSetCoordinateMap(dm, NULL));
539361a622f3SMatthew G. Knepley     }
5394c3db174cSMatthew G. Knepley     PetscCall(PetscOptionsBool("-dm_localize", "Localize mesh coordinates", "", localize, &localize, NULL));
5395c3db174cSMatthew G. Knepley     PetscCall(PetscOptionsBool("-dm_sparse_localize", "Localize only necessary cells", "DMSetSparseLocalize", sparseLocalize, &sparseLocalize, &flg));
5396c3db174cSMatthew G. Knepley     if (flg) PetscCall(DMSetSparseLocalize(dm, sparseLocalize));
53975515ebd3SMatthew G. Knepley     PetscCall(PetscOptionsInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", height, &height, &flg));
53985515ebd3SMatthew G. Knepley     if (flg) PetscCall(DMPlexSetMaxProjectionHeight(cdm, height));
5399c3db174cSMatthew G. Knepley     if (localize) PetscCall(DMLocalizeCoordinates(dm));
54009318fe57SMatthew G. Knepley   }
540168d4fef7SMatthew G. Knepley   /* Handle DMPlex refinement */
540261a622f3SMatthew G. Knepley   remap = PETSC_TRUE;
54039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_refine", "The number of uniform refinements", "DMCreate", refine, &refine, NULL, 0));
54049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_refine_remap", "Flag to control coordinate remapping", "DMCreate", remap, &remap, NULL));
54059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy", "The number of uniform refinements", "DMCreate", refine, &refine, &isHierarchy, 0));
54069566063dSJacob Faibussowitsch   if (refine) PetscCall(DMPlexSetRefinementUniform(dm, PETSC_TRUE));
540768d4fef7SMatthew G. Knepley   if (refine && isHierarchy) {
5408acdc6f61SToby Isaac     DM *dms, coarseDM;
540968d4fef7SMatthew G. Knepley 
54109566063dSJacob Faibussowitsch     PetscCall(DMGetCoarseDM(dm, &coarseDM));
54119566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)coarseDM));
54129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(refine, &dms));
54139566063dSJacob Faibussowitsch     PetscCall(DMRefineHierarchy(dm, refine, dms));
541468d4fef7SMatthew G. Knepley     /* Total hack since we do not pass in a pointer */
54159566063dSJacob Faibussowitsch     PetscCall(DMPlexSwap_Static(dm, dms[refine - 1]));
541668d4fef7SMatthew G. Knepley     if (refine == 1) {
54179566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, dms[0]));
54189566063dSJacob Faibussowitsch       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
541968d4fef7SMatthew G. Knepley     } else {
54209566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, dms[refine - 2]));
54219566063dSJacob Faibussowitsch       PetscCall(DMPlexSetRegularRefinement(dm, PETSC_TRUE));
54229566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dms[0], dms[refine - 1]));
54239566063dSJacob Faibussowitsch       PetscCall(DMPlexSetRegularRefinement(dms[0], PETSC_TRUE));
542468d4fef7SMatthew G. Knepley     }
54259566063dSJacob Faibussowitsch     PetscCall(DMSetCoarseDM(dms[refine - 1], coarseDM));
54269566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)coarseDM));
542768d4fef7SMatthew G. Knepley     /* Free DMs */
542868d4fef7SMatthew G. Knepley     for (r = 0; r < refine; ++r) {
5429dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
54309566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dms[r]));
543168d4fef7SMatthew G. Knepley     }
54329566063dSJacob Faibussowitsch     PetscCall(PetscFree(dms));
543368d4fef7SMatthew G. Knepley   } else {
543468d4fef7SMatthew G. Knepley     for (r = 0; r < refine; ++r) {
54359318fe57SMatthew G. Knepley       DM            rdm;
54362192575eSBarry Smith       PetscPointFn *coordFunc;
543768d4fef7SMatthew G. Knepley 
5438dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
54399566063dSJacob Faibussowitsch       PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &rdm));
544068d4fef7SMatthew G. Knepley       /* Total hack since we do not pass in a pointer */
544169d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &rdm));
5442dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
54433674be70SMatthew G. Knepley       PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
544461a622f3SMatthew G. Knepley       if (coordFunc && remap) {
54459566063dSJacob Faibussowitsch         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5446509b31aaSMatthew G. Knepley         PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
544751a74b61SMatthew G. Knepley       }
544868d4fef7SMatthew G. Knepley     }
544968d4fef7SMatthew G. Knepley   }
54503cf6fe12SMatthew G. Knepley   /* Handle DMPlex coarsening */
54519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_coarsen", "Coarsen the mesh", "DMCreate", coarsen, &coarsen, NULL, 0));
54529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_coarsen_hierarchy", "The number of coarsenings", "DMCreate", coarsen, &coarsen, &isHierarchy, 0));
5453b653a561SMatthew G. Knepley   if (coarsen && isHierarchy) {
5454b653a561SMatthew G. Knepley     DM *dms;
5455b653a561SMatthew G. Knepley 
54569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(coarsen, &dms));
54579566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHierarchy(dm, coarsen, dms));
5458b653a561SMatthew G. Knepley     /* Free DMs */
5459b653a561SMatthew G. Knepley     for (r = 0; r < coarsen; ++r) {
5460dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dms[r], PetscOptionsObject));
54619566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dms[r]));
5462b653a561SMatthew G. Knepley     }
54639566063dSJacob Faibussowitsch     PetscCall(PetscFree(dms));
5464b653a561SMatthew G. Knepley   } else {
5465b653a561SMatthew G. Knepley     for (r = 0; r < coarsen; ++r) {
54669318fe57SMatthew G. Knepley       DM            cdm;
54672192575eSBarry Smith       PetscPointFn *coordFunc;
54683cf6fe12SMatthew G. Knepley 
5469509b31aaSMatthew G. Knepley       PetscCall(DMPlexGetCoordinateMap(dm, &coordFunc));
5470dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
54719566063dSJacob Faibussowitsch       PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &cdm));
54723cf6fe12SMatthew G. Knepley       /* Total hack since we do not pass in a pointer */
547369d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &cdm));
5474dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
54759318fe57SMatthew G. Knepley       if (coordFunc) {
54769566063dSJacob Faibussowitsch         PetscCall(DMPlexRemapGeometry(dm, 0.0, coordFunc));
5477509b31aaSMatthew G. Knepley         PetscCall(DMPlexSetCoordinateMap(dm, coordFunc));
54789318fe57SMatthew G. Knepley       }
54793cf6fe12SMatthew G. Knepley     }
5480b653a561SMatthew G. Knepley   }
5481be664eb1SMatthew G. Knepley   // Handle coordinate remapping
5482be664eb1SMatthew G. Knepley   remap = PETSC_FALSE;
5483be664eb1SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_coord_remap", "Flag to control coordinate remapping", "", remap, &remap, NULL));
5484be664eb1SMatthew G. Knepley   if (remap) {
5485be664eb1SMatthew G. Knepley     DMPlexCoordMap map     = DM_COORD_MAP_NONE;
54862192575eSBarry Smith     PetscPointFn  *mapFunc = NULL;
5487be664eb1SMatthew G. Knepley     PetscScalar    params[16];
5488f45b553cSPierre Jolivet     PetscInt       Np = PETSC_STATIC_ARRAY_LENGTH(params), cdim;
5489be664eb1SMatthew G. Knepley     MPI_Comm       comm;
5490be664eb1SMatthew G. Knepley 
5491be664eb1SMatthew G. Knepley     PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5492be664eb1SMatthew G. Knepley     PetscCall(DMGetCoordinateDim(dm, &cdim));
5493be664eb1SMatthew G. Knepley     PetscCall(PetscOptionsScalarArray("-dm_coord_map_params", "Parameters for the coordinate remapping", "", params, &Np, &flg));
5494be664eb1SMatthew G. Knepley     if (!flg) Np = 0;
5495be664eb1SMatthew G. Knepley     // TODO Allow user to pass a map function by name
5496be664eb1SMatthew G. Knepley     PetscCall(PetscOptionsEnum("-dm_coord_map", "Coordinate mapping for built-in mesh", "", DMPlexCoordMaps, (PetscEnum)map, (PetscEnum *)&map, &flg));
5497be664eb1SMatthew G. Knepley     if (flg) {
5498be664eb1SMatthew G. Knepley       switch (map) {
5499be664eb1SMatthew G. Knepley       case DM_COORD_MAP_NONE:
5500be664eb1SMatthew G. Knepley         mapFunc = coordMap_identity;
5501be664eb1SMatthew G. Knepley         break;
5502be664eb1SMatthew G. Knepley       case DM_COORD_MAP_SHEAR:
5503be664eb1SMatthew G. Knepley         mapFunc = coordMap_shear;
5504be664eb1SMatthew G. Knepley         if (!Np) {
5505be664eb1SMatthew G. Knepley           Np        = cdim + 1;
5506be664eb1SMatthew G. Knepley           params[0] = 0;
5507be664eb1SMatthew G. Knepley           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
5508be664eb1SMatthew G. Knepley         }
5509be664eb1SMatthew G. Knepley         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The shear coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
5510be664eb1SMatthew G. Knepley         break;
5511be664eb1SMatthew G. Knepley       case DM_COORD_MAP_FLARE:
5512be664eb1SMatthew G. Knepley         mapFunc = coordMap_flare;
5513be664eb1SMatthew G. Knepley         if (!Np) {
5514be664eb1SMatthew G. Knepley           Np        = cdim + 1;
5515be664eb1SMatthew G. Knepley           params[0] = 0;
5516be664eb1SMatthew G. Knepley           for (PetscInt d = 1; d <= cdim; ++d) params[d] = 1.0;
5517be664eb1SMatthew G. Knepley         }
5518be664eb1SMatthew G. Knepley         PetscCheck(Np == cdim + 1, comm, PETSC_ERR_ARG_WRONG, "The flare coordinate map must have cdim + 1 = %" PetscInt_FMT " parameters, not %" PetscInt_FMT, cdim + 1, Np);
5519be664eb1SMatthew G. Knepley         break;
5520be664eb1SMatthew G. Knepley       case DM_COORD_MAP_ANNULUS:
5521be664eb1SMatthew G. Knepley         mapFunc = coordMap_annulus;
5522be664eb1SMatthew G. Knepley         if (!Np) {
5523be664eb1SMatthew G. Knepley           Np        = 2;
5524be664eb1SMatthew G. Knepley           params[0] = 1.;
5525be664eb1SMatthew G. Knepley           params[1] = 2.;
5526be664eb1SMatthew G. Knepley         }
5527be664eb1SMatthew G. Knepley         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The annulus coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
5528be664eb1SMatthew G. Knepley         break;
5529be664eb1SMatthew G. Knepley       case DM_COORD_MAP_SHELL:
5530be664eb1SMatthew G. Knepley         mapFunc = coordMap_shell;
5531be664eb1SMatthew G. Knepley         if (!Np) {
5532be664eb1SMatthew G. Knepley           Np        = 2;
5533be664eb1SMatthew G. Knepley           params[0] = 1.;
5534be664eb1SMatthew G. Knepley           params[1] = 2.;
5535be664eb1SMatthew G. Knepley         }
5536be664eb1SMatthew G. Knepley         PetscCheck(Np == 2, comm, PETSC_ERR_ARG_WRONG, "The spherical shell coordinate map must have 2 parameters, not %" PetscInt_FMT, Np);
5537be664eb1SMatthew G. Knepley         break;
5538530e699aSMatthew G. Knepley       case DM_COORD_MAP_SINUSOID:
5539530e699aSMatthew G. Knepley         mapFunc = coordMap_sinusoid;
5540530e699aSMatthew G. Knepley         if (!Np) {
5541530e699aSMatthew G. Knepley           Np        = 3;
5542530e699aSMatthew G. Knepley           params[0] = 1.;
5543530e699aSMatthew G. Knepley           params[1] = 1.;
5544530e699aSMatthew G. Knepley           params[2] = 1.;
5545530e699aSMatthew G. Knepley         }
5546530e699aSMatthew G. Knepley         PetscCheck(Np == 3, comm, PETSC_ERR_ARG_WRONG, "The sinusoidal coordinate map must have 3 parameters, not %" PetscInt_FMT, Np);
5547530e699aSMatthew G. Knepley         break;
5548be664eb1SMatthew G. Knepley       default:
5549be664eb1SMatthew G. Knepley         mapFunc = coordMap_identity;
5550be664eb1SMatthew G. Knepley       }
5551be664eb1SMatthew G. Knepley     }
5552be664eb1SMatthew G. Knepley     if (Np) {
5553be664eb1SMatthew G. Knepley       DM      cdm;
5554be664eb1SMatthew G. Knepley       PetscDS cds;
5555be664eb1SMatthew G. Knepley 
5556be664eb1SMatthew G. Knepley       PetscCall(DMGetCoordinateDM(dm, &cdm));
5557be664eb1SMatthew G. Knepley       PetscCall(DMGetDS(cdm, &cds));
5558be664eb1SMatthew G. Knepley       PetscCall(PetscDSSetConstants(cds, Np, params));
5559be664eb1SMatthew G. Knepley     }
5560be664eb1SMatthew G. Knepley     PetscCall(DMPlexRemapGeometry(dm, 0.0, mapFunc));
5561be664eb1SMatthew G. Knepley   }
5562909dfd52SMatthew G. Knepley   /* Handle ghost cells */
55639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_create_fv_ghost_cells", "Flag to create finite volume ghost cells on the boundary", "DMCreate", ghostCells, &ghostCells, NULL));
5564909dfd52SMatthew G. Knepley   if (ghostCells) {
5565909dfd52SMatthew G. Knepley     DM   gdm;
5566909dfd52SMatthew G. Knepley     char lname[PETSC_MAX_PATH_LEN];
5567909dfd52SMatthew G. Knepley 
5568909dfd52SMatthew G. Knepley     lname[0] = '\0';
55699566063dSJacob Faibussowitsch     PetscCall(PetscOptionsString("-dm_plex_fv_ghost_cells_label", "Label name for ghost cells boundary", "DMCreate", lname, lname, sizeof(lname), &flg));
55709566063dSJacob Faibussowitsch     PetscCall(DMPlexConstructGhostCells(dm, flg ? lname : NULL, NULL, &gdm));
557169d8a87bSksagiyam     PetscCall(DMPlexReplace_Internal(dm, &gdm));
5572909dfd52SMatthew G. Knepley   }
55736913077dSMatthew G. Knepley   /* Handle 1D order */
5574adc21957SMatthew G. Knepley   if (reorder != DM_REORDER_DEFAULT_FALSE && dim == 1) {
55756913077dSMatthew G. Knepley     DM           cdm, rdm;
55766913077dSMatthew G. Knepley     PetscDS      cds;
55776913077dSMatthew G. Knepley     PetscObject  obj;
55786913077dSMatthew G. Knepley     PetscClassId id = PETSC_OBJECT_CLASSID;
55796913077dSMatthew G. Knepley     IS           perm;
55806bc1bd01Sksagiyam     PetscInt     Nf;
55816913077dSMatthew G. Knepley     PetscBool    distributed;
55826913077dSMatthew G. Knepley 
55839566063dSJacob Faibussowitsch     PetscCall(DMPlexIsDistributed(dm, &distributed));
55849566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(dm, &cdm));
55859566063dSJacob Faibussowitsch     PetscCall(DMGetDS(cdm, &cds));
55869566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(cds, &Nf));
55876913077dSMatthew G. Knepley     if (Nf) {
55889566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(cds, 0, &obj));
55899566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
55906913077dSMatthew G. Knepley     }
55916bc1bd01Sksagiyam     if (!distributed && id != PETSCFE_CLASSID) {
55929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetOrdering1D(dm, &perm));
55939566063dSJacob Faibussowitsch       PetscCall(DMPlexPermute(dm, perm, &rdm));
559469d8a87bSksagiyam       PetscCall(DMPlexReplace_Internal(dm, &rdm));
55959566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&perm));
55966913077dSMatthew G. Knepley     }
55976913077dSMatthew G. Knepley   }
55983cf6fe12SMatthew G. Knepley /* Handle */
5599dd4c3f67SMatthew G. Knepley non_refine:
5600dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_NonRefinement_Plex(dm, PetscOptionsObject));
560122d6dc08SStefano Zampini   char    *phases[16];
560222d6dc08SStefano Zampini   PetscInt Nphases = 16;
560322d6dc08SStefano Zampini   PetscCall(PetscOptionsStringArray("-dm_plex_option_phases", "Option phase prefixes", "DMSetFromOptions", phases, &Nphases, &flg));
5604d0609cedSBarry Smith   PetscOptionsHeadEnd();
560522d6dc08SStefano Zampini 
560622d6dc08SStefano Zampini   // Phases
560722d6dc08SStefano Zampini   if (flg) {
5608530e699aSMatthew G. Knepley     DM          cdm;
5609530e699aSMatthew G. Knepley     char       *oldPrefix, *oldCoordPrefix;
5610530e699aSMatthew G. Knepley     const char *tmp;
561122d6dc08SStefano Zampini 
5612530e699aSMatthew G. Knepley     PetscCall(DMGetCoordinateDM(dm, &cdm));
5613530e699aSMatthew G. Knepley     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &tmp));
5614530e699aSMatthew G. Knepley     PetscCall(PetscStrallocpy(tmp, &oldPrefix));
5615530e699aSMatthew G. Knepley     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdm, &tmp));
5616530e699aSMatthew G. Knepley     PetscCall(PetscStrallocpy(tmp, &oldCoordPrefix));
561722d6dc08SStefano Zampini     for (PetscInt ph = 0; ph < Nphases; ++ph) {
561822d6dc08SStefano Zampini       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, phases[ph]));
5619530e699aSMatthew G. Knepley       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)cdm, phases[ph]));
562022d6dc08SStefano Zampini       PetscCall(PetscInfo(dm, "Options phase %s for DM %s\n", phases[ph], dm->hdr.name));
562122d6dc08SStefano Zampini       PetscCall(DMSetFromOptions(dm));
562222d6dc08SStefano Zampini       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oldPrefix));
5623530e699aSMatthew G. Knepley       PetscCall(DMGetCoordinateDM(dm, &cdm));
5624530e699aSMatthew G. Knepley       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdm, oldCoordPrefix));
562522d6dc08SStefano Zampini       PetscCall(PetscFree(phases[ph]));
562622d6dc08SStefano Zampini     }
5627530e699aSMatthew G. Knepley     PetscCall(PetscFree(oldPrefix));
5628530e699aSMatthew G. Knepley     PetscCall(PetscFree(oldCoordPrefix));
562922d6dc08SStefano Zampini   }
56303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56310a6ba040SMatthew G. Knepley }
56320a6ba040SMatthew G. Knepley 
5633d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_Plex(DM dm, Vec *vec)
5634d71ae5a4SJacob Faibussowitsch {
5635552f7358SJed Brown   PetscFunctionBegin;
56369566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
56379566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
563857d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Plex));
563957d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (PetscErrorCodeFn *)VecView_Plex_Native));
564057d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (PetscErrorCodeFn *)VecLoad_Plex));
564157d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (PetscErrorCodeFn *)VecLoad_Plex_Native));
56423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5643552f7358SJed Brown }
5644552f7358SJed Brown 
5645d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_Plex(DM dm, Vec *vec)
5646d71ae5a4SJacob Faibussowitsch {
5647552f7358SJed Brown   PetscFunctionBegin;
56489566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
564957d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (PetscErrorCodeFn *)VecView_Plex_Local));
565057d50842SBarry Smith   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (PetscErrorCodeFn *)VecLoad_Plex_Local));
56513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5652552f7358SJed Brown }
5653552f7358SJed Brown 
5654d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetDimPoints_Plex(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5655d71ae5a4SJacob Faibussowitsch {
5656793f3fe5SMatthew G. Knepley   PetscInt depth, d;
5657793f3fe5SMatthew G. Knepley 
5658793f3fe5SMatthew G. Knepley   PetscFunctionBegin;
56599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
5660793f3fe5SMatthew G. Knepley   if (depth == 1) {
56619566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &d));
56629566063dSJacob Faibussowitsch     if (dim == 0) PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
56639566063dSJacob Faibussowitsch     else if (dim == d) PetscCall(DMPlexGetDepthStratum(dm, 1, pStart, pEnd));
56649371c9d4SSatish Balay     else {
56659371c9d4SSatish Balay       *pStart = 0;
56669371c9d4SSatish Balay       *pEnd   = 0;
56679371c9d4SSatish Balay     }
5668793f3fe5SMatthew G. Knepley   } else {
56699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, pStart, pEnd));
5670793f3fe5SMatthew G. Knepley   }
56713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5672793f3fe5SMatthew G. Knepley }
5673793f3fe5SMatthew G. Knepley 
5674d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetNeighbors_Plex(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
5675d71ae5a4SJacob Faibussowitsch {
5676502a2867SDave May   PetscSF            sf;
56776497c311SBarry Smith   PetscMPIInt        niranks, njranks;
56786497c311SBarry Smith   PetscInt           n;
56790a19bb7dSprj-   const PetscMPIInt *iranks, *jranks;
56800a19bb7dSprj-   DM_Plex           *data = (DM_Plex *)dm->data;
5681502a2867SDave May 
56822f356facSMatthew G. Knepley   PetscFunctionBegin;
56839566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
56840a19bb7dSprj-   if (!data->neighbors) {
56859566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
56869566063dSJacob Faibussowitsch     PetscCall(PetscSFGetRootRanks(sf, &njranks, &jranks, NULL, NULL, NULL));
56879566063dSJacob Faibussowitsch     PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, NULL, NULL));
56889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(njranks + niranks + 1, &data->neighbors));
56899566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data->neighbors + 1, jranks, njranks));
56909566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(data->neighbors + njranks + 1, iranks, niranks));
56910a19bb7dSprj-     n = njranks + niranks;
56929566063dSJacob Faibussowitsch     PetscCall(PetscSortRemoveDupsMPIInt(&n, data->neighbors + 1));
56930a19bb7dSprj-     /* The following cast should never fail: can't have more neighbors than PETSC_MPI_INT_MAX */
56949566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(n, data->neighbors));
56950a19bb7dSprj-   }
56960a19bb7dSprj-   if (nranks) *nranks = data->neighbors[0];
56970a19bb7dSprj-   if (ranks) {
56980a19bb7dSprj-     if (data->neighbors[0]) *ranks = data->neighbors + 1;
56990a19bb7dSprj-     else *ranks = NULL;
57000a19bb7dSprj-   }
57013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5702502a2867SDave May }
5703502a2867SDave May 
57041eb70e55SToby Isaac PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM, DM, Mat, Vec, Vec);
57051eb70e55SToby Isaac 
5706d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_Plex(DM dm)
5707d71ae5a4SJacob Faibussowitsch {
5708552f7358SJed Brown   PetscFunctionBegin;
5709552f7358SJed Brown   dm->ops->view                      = DMView_Plex;
57102c40f234SMatthew G. Knepley   dm->ops->load                      = DMLoad_Plex;
5711552f7358SJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_Plex;
571238221697SMatthew G. Knepley   dm->ops->clone                     = DMClone_Plex;
5713552f7358SJed Brown   dm->ops->setup                     = DMSetUp_Plex;
57141bb6d2a8SBarry Smith   dm->ops->createlocalsection        = DMCreateLocalSection_Plex;
5715adc21957SMatthew G. Knepley   dm->ops->createsectionpermutation  = DMCreateSectionPermutation_Plex;
571666ad2231SToby Isaac   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_Plex;
5717552f7358SJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_Plex;
5718552f7358SJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_Plex;
5719184d77edSJed Brown   dm->ops->getlocaltoglobalmapping   = NULL;
57200298fd71SBarry Smith   dm->ops->createfieldis             = NULL;
5721552f7358SJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_Plex;
572299acd26cSksagiyam   dm->ops->createcellcoordinatedm    = DMCreateCellCoordinateDM_Plex;
5723f19dbd58SToby Isaac   dm->ops->createcoordinatefield     = DMCreateCoordinateField_Plex;
57240a6ba040SMatthew G. Knepley   dm->ops->getcoloring               = NULL;
5725552f7358SJed Brown   dm->ops->creatematrix              = DMCreateMatrix_Plex;
5726bceba477SMatthew G. Knepley   dm->ops->createinterpolation       = DMCreateInterpolation_Plex;
5727bd041c0cSMatthew G. Knepley   dm->ops->createmassmatrix          = DMCreateMassMatrix_Plex;
5728b4937a87SMatthew G. Knepley   dm->ops->createmassmatrixlumped    = DMCreateMassMatrixLumped_Plex;
57291898fd5cSMatthew G. Knepley   dm->ops->creategradientmatrix      = DMCreateGradientMatrix_Plex;
57305a84ad33SLisandro Dalcin   dm->ops->createinjection           = DMCreateInjection_Plex;
5731552f7358SJed Brown   dm->ops->refine                    = DMRefine_Plex;
57320a6ba040SMatthew G. Knepley   dm->ops->coarsen                   = DMCoarsen_Plex;
57330a6ba040SMatthew G. Knepley   dm->ops->refinehierarchy           = DMRefineHierarchy_Plex;
5734b653a561SMatthew G. Knepley   dm->ops->coarsenhierarchy          = DMCoarsenHierarchy_Plex;
5735d410b0cfSMatthew G. Knepley   dm->ops->extrude                   = DMExtrude_Plex;
57360298fd71SBarry Smith   dm->ops->globaltolocalbegin        = NULL;
57370298fd71SBarry Smith   dm->ops->globaltolocalend          = NULL;
57380298fd71SBarry Smith   dm->ops->localtoglobalbegin        = NULL;
57390298fd71SBarry Smith   dm->ops->localtoglobalend          = NULL;
5740552f7358SJed Brown   dm->ops->destroy                   = DMDestroy_Plex;
5741552f7358SJed Brown   dm->ops->createsubdm               = DMCreateSubDM_Plex;
57422adcc780SMatthew G. Knepley   dm->ops->createsuperdm             = DMCreateSuperDM_Plex;
5743793f3fe5SMatthew G. Knepley   dm->ops->getdimpoints              = DMGetDimPoints_Plex;
5744552f7358SJed Brown   dm->ops->locatepoints              = DMLocatePoints_Plex;
57450709b2feSToby Isaac   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_Plex;
57460709b2feSToby Isaac   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_Plex;
5747bfc4295aSToby Isaac   dm->ops->projectfieldlocal         = DMProjectFieldLocal_Plex;
57488c6c5593SMatthew G. Knepley   dm->ops->projectfieldlabellocal    = DMProjectFieldLabelLocal_Plex;
5749ece3a9fcSMatthew G. Knepley   dm->ops->projectbdfieldlabellocal  = DMProjectBdFieldLabelLocal_Plex;
57500709b2feSToby Isaac   dm->ops->computel2diff             = DMComputeL2Diff_Plex;
5751b698f381SToby Isaac   dm->ops->computel2gradientdiff     = DMComputeL2GradientDiff_Plex;
57522a16baeaSToby Isaac   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_Plex;
575328d58a37SPierre Jolivet   dm->ops->getneighbors              = DMGetNeighbors_Plex;
57546c6a6b79SMatthew G. Knepley   dm->ops->getlocalboundingbox       = DMGetLocalBoundingBox_Coordinates;
5755907a3e9cSStefano Zampini   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_Plex;
5756907a3e9cSStefano Zampini   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_Plex;
57579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_Plex));
57586c51210dSStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", DMPlexInsertTimeDerivativeBoundaryValues_Plex));
575901468941SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBounds_C", DMPlexInsertBounds_Plex));
57609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Plex));
57619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_Plex));
57629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", DMPlexDistributeGetDefault_Plex));
57639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", DMPlexDistributeSetDefault_Plex));
57646bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", DMPlexReorderGetDefault_Plex));
57656bc1bd01Sksagiyam   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", DMPlexReorderSetDefault_Plex));
5766adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", DMReorderSectionGetDefault_Plex));
5767adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", DMReorderSectionSetDefault_Plex));
5768adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", DMReorderSectionGetType_Plex));
5769adc21957SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", DMReorderSectionSetType_Plex));
57709566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", DMInterpolateSolution_Plex));
5771c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMPlexGetOverlap_Plex));
5772c506a872SMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", DMPlexSetOverlap_Plex));
5773d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", DMPlexGetUseCeed_Plex));
5774d2b2dc1eSMatthew G. Knepley   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", DMPlexSetUseCeed_Plex));
57753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5776552f7358SJed Brown }
5777552f7358SJed Brown 
5778d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode DMClone_Plex(DM dm, DM *newdm)
5779d71ae5a4SJacob Faibussowitsch {
578063a16f15SMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *)dm->data;
57811fca310dSJames Wright   const PetscSF *face_sfs;
57821fca310dSJames Wright   PetscInt       num_face_sfs;
578363a16f15SMatthew G. Knepley 
578463a16f15SMatthew G. Knepley   PetscFunctionBegin;
578563a16f15SMatthew G. Knepley   mesh->refct++;
578663a16f15SMatthew G. Knepley   (*newdm)->data = mesh;
57871fca310dSJames Wright   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, &face_sfs));
57881fca310dSJames Wright   PetscCall(DMPlexSetIsoperiodicFaceSF(*newdm, num_face_sfs, (PetscSF *)face_sfs));
57899566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMPLEX));
57909566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Plex(*newdm));
57913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
579263a16f15SMatthew G. Knepley }
579363a16f15SMatthew G. Knepley 
57948818961aSMatthew G Knepley /*MC
57950b4b7b1cSBarry Smith   DMPLEX = "plex" - A `DM` object that encapsulates an unstructured mesh (or grid), or CW Complex {cite}`cwcomplex`,
57960b4b7b1cSBarry Smith            which can be expressed using a Hasse Diagram {cite}`hassediagram`.
579720f4b53cSBarry Smith            In the local representation, `Vec`s contain all unknowns in the interior and shared boundary. This is
57980b4b7b1cSBarry Smith            specified by a `PetscSection` object. Ownership in the global representation is determined by
5799a1cb98faSBarry Smith            ownership of the underlying `DMPLEX` points. This is specified by another `PetscSection` object.
58008818961aSMatthew G Knepley 
5801e5893cccSMatthew G. Knepley   Options Database Keys:
5802250712c9SMatthew G. Knepley + -dm_refine_pre                     - Refine mesh before distribution
5803250712c9SMatthew G. Knepley + -dm_refine_uniform_pre             - Choose uniform or generator-based refinement
5804250712c9SMatthew G. Knepley + -dm_refine_volume_limit_pre        - Cell volume limit after pre-refinement using generator
5805250712c9SMatthew G. Knepley . -dm_distribute                     - Distribute mesh across processes
5806250712c9SMatthew G. Knepley . -dm_distribute_overlap             - Number of cells to overlap for distribution
5807250712c9SMatthew G. Knepley . -dm_refine                         - Refine mesh after distribution
5808c3db174cSMatthew G. Knepley . -dm_localize <bool>                - Whether to localize coordinates for periodic meshes
5809c3db174cSMatthew G. Knepley . -dm_sparse_localize <bool>         - Whether to only localize cells on the periodic boundary
5810250712c9SMatthew G. Knepley . -dm_plex_hash_location             - Use grid hashing for point location
5811ddce0771SMatthew G. Knepley . -dm_plex_hash_box_faces <n,m,p>    - The number of divisions in each direction of the grid hash
5812f12cf164SMatthew G. Knepley . -dm_plex_partition_balance         - Attempt to evenly divide points on partition boundary between processes
5813f12cf164SMatthew G. Knepley . -dm_plex_remesh_bd                 - Allow changes to the boundary on remeshing
5814d5b43468SJose E. Roman . -dm_plex_max_projection_height     - Maximum mesh point height used to project locally
5815f12cf164SMatthew G. Knepley . -dm_plex_regular_refinement        - Use special nested projection algorithm for regular refinement
5816d02c7345SMatthew G. Knepley . -dm_plex_reorder_section           - Use specialized blocking if available
5817aaa8cc7dSPierre Jolivet . -dm_plex_check_all                 - Perform all checks below
5818f12cf164SMatthew G. Knepley . -dm_plex_check_symmetry            - Check that the adjacency information in the mesh is symmetric
5819f12cf164SMatthew G. Knepley . -dm_plex_check_skeleton <celltype> - Check that each cell has the correct number of vertices
5820f12cf164SMatthew G. Knepley . -dm_plex_check_faces <celltype>    - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5821f12cf164SMatthew G. Knepley . -dm_plex_check_geometry            - Check that cells have positive volume
5822f12cf164SMatthew G. Knepley . -dm_view :mesh.tex:ascii_latex     - View the mesh in LaTeX/TikZ
5823e5893cccSMatthew G. Knepley . -dm_plex_view_scale <num>          - Scale the TikZ
58245962854dSMatthew G. Knepley . -dm_plex_print_fem <num>           - View FEM assembly information, such as element vectors and matrices
58255962854dSMatthew G. Knepley - -dm_plex_print_fvm <num>           - View FVM assembly information, such as flux updates
5826e5893cccSMatthew G. Knepley 
58278818961aSMatthew G Knepley   Level: intermediate
58288818961aSMatthew G Knepley 
58291cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMPlexCreate()`, `DMCreate()`, `DMSetType()`, `PetscSection`
58308818961aSMatthew G Knepley M*/
58318818961aSMatthew G Knepley 
5832d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_Plex(DM dm)
5833d71ae5a4SJacob Faibussowitsch {
5834552f7358SJed Brown   DM_Plex *mesh;
5835412e9a14SMatthew G. Knepley   PetscInt unit;
5836552f7358SJed Brown 
5837552f7358SJed Brown   PetscFunctionBegin;
5838f39ec787SMatthew G. Knepley   PetscCall(PetscCitationsRegister(PlexCitation, &Plexcite));
5839552f7358SJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58404dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mesh));
5841adc21957SMatthew G. Knepley   dm->reorderSection = DM_REORDER_DEFAULT_NOTSET;
5842552f7358SJed Brown   dm->data           = mesh;
5843552f7358SJed Brown 
5844552f7358SJed Brown   mesh->refct = 1;
58459566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->coneSection));
58469566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &mesh->supportSection));
5847552f7358SJed Brown   mesh->refinementUniform       = PETSC_TRUE;
5848552f7358SJed Brown   mesh->refinementLimit         = -1.0;
5849e600fa54SMatthew G. Knepley   mesh->distDefault             = PETSC_TRUE;
5850adc21957SMatthew G. Knepley   mesh->reorderDefault          = DM_REORDER_DEFAULT_NOTSET;
58511d1f2f2aSksagiyam   mesh->distributionName        = NULL;
58527d0f5628SVaclav Hapla   mesh->interpolated            = DMPLEX_INTERPOLATED_INVALID;
58537d0f5628SVaclav Hapla   mesh->interpolatedCollective  = DMPLEX_INTERPOLATED_INVALID;
58545e2c5519SMatthew G. Knepley   mesh->interpolatePreferTensor = PETSC_TRUE;
5855552f7358SJed Brown 
58569566063dSJacob Faibussowitsch   PetscCall(PetscPartitionerCreate(PetscObjectComm((PetscObject)dm), &mesh->partitioner));
58572e62ab5aSMatthew G. Knepley   mesh->remeshBd = PETSC_FALSE;
5858d9deefdfSMatthew G. Knepley 
58598865f1eaSKarl Rupp   for (unit = 0; unit < NUM_PETSC_UNITS; ++unit) mesh->scale[unit] = 1.0;
5860552f7358SJed Brown 
5861df0420ecSMatthew G. Knepley   mesh->depthState    = -1;
5862ba2698f1SMatthew G. Knepley   mesh->celltypeState = -1;
58636113b454SMatthew G. Knepley   mesh->printTol      = 1.0e-10;
5864c29ce622SStefano Zampini   mesh->nonempty_comm = MPI_COMM_SELF;
5865552f7358SJed Brown 
58669566063dSJacob Faibussowitsch   PetscCall(DMInitialize_Plex(dm));
58673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5868552f7358SJed Brown }
5869552f7358SJed Brown 
5870552f7358SJed Brown /*@
5871a1cb98faSBarry Smith   DMPlexCreate - Creates a `DMPLEX` object, which encapsulates an unstructured mesh, or CW complex, which can be expressed using a Hasse Diagram.
5872552f7358SJed Brown 
5873d083f849SBarry Smith   Collective
5874552f7358SJed Brown 
5875552f7358SJed Brown   Input Parameter:
5876a1cb98faSBarry Smith . comm - The communicator for the `DMPLEX` object
5877552f7358SJed Brown 
5878552f7358SJed Brown   Output Parameter:
5879a1cb98faSBarry Smith . mesh - The `DMPLEX` object
5880552f7358SJed Brown 
5881552f7358SJed Brown   Level: beginner
5882552f7358SJed Brown 
588342747ad1SJacob Faibussowitsch .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMType`, `DMCreate()`, `DMSetType()`
5884552f7358SJed Brown @*/
5885d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreate(MPI_Comm comm, DM *mesh)
5886d71ae5a4SJacob Faibussowitsch {
5887552f7358SJed Brown   PetscFunctionBegin;
58884f572ea9SToby Isaac   PetscAssertPointer(mesh, 2);
58899566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, mesh));
58909566063dSJacob Faibussowitsch   PetscCall(DMSetType(*mesh, DMPLEX));
58913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5892552f7358SJed Brown }
5893552f7358SJed Brown 
5894b09969d6SVaclav Hapla /*@C
5895e1b2f275SBarry Smith   DMPlexBuildFromCellListParallel - Build a distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype
5896a1cb98faSBarry Smith 
589720f4b53cSBarry Smith   Collective; No Fortran Support
5898b09969d6SVaclav Hapla 
5899b09969d6SVaclav Hapla   Input Parameters:
5900a1cb98faSBarry Smith + dm          - The `DM`
5901b09969d6SVaclav Hapla . numCells    - The number of cells owned by this process
5902a1cb98faSBarry Smith . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
5903a1cb98faSBarry Smith . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
5904b09969d6SVaclav Hapla . numCorners  - The number of vertices for each cell
5905e1b2f275SBarry Smith - cells       - An array of $ numCells \times numCorners$ numbers, the global vertex numbers for each cell
5906b09969d6SVaclav Hapla 
5907be8c289dSNicolas Barral   Output Parameters:
5908a1cb98faSBarry Smith + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
5909be8c289dSNicolas Barral - verticesAdjSaved - (Optional) vertex adjacency array
5910b09969d6SVaclav Hapla 
5911b09969d6SVaclav Hapla   Level: advanced
5912b09969d6SVaclav Hapla 
5913a1cb98faSBarry Smith   Notes:
5914a1cb98faSBarry Smith   Two triangles sharing a face
5915a1cb98faSBarry Smith .vb
5916a1cb98faSBarry Smith 
5917a1cb98faSBarry Smith         2
5918a1cb98faSBarry Smith       / | \
5919a1cb98faSBarry Smith      /  |  \
5920a1cb98faSBarry Smith     /   |   \
5921a1cb98faSBarry Smith    0  0 | 1  3
5922a1cb98faSBarry Smith     \   |   /
5923a1cb98faSBarry Smith      \  |  /
5924a1cb98faSBarry Smith       \ | /
5925a1cb98faSBarry Smith         1
5926a1cb98faSBarry Smith .ve
5927a1cb98faSBarry Smith   would have input
5928a1cb98faSBarry Smith .vb
5929a1cb98faSBarry Smith   numCells = 2, numVertices = 4
5930a1cb98faSBarry Smith   cells = [0 1 2  1 3 2]
5931a1cb98faSBarry Smith .ve
5932a1cb98faSBarry Smith   which would result in the `DMPLEX`
5933a1cb98faSBarry Smith .vb
5934a1cb98faSBarry Smith 
5935a1cb98faSBarry Smith         4
5936a1cb98faSBarry Smith       / | \
5937a1cb98faSBarry Smith      /  |  \
5938a1cb98faSBarry Smith     /   |   \
5939a1cb98faSBarry Smith    2  0 | 1  5
5940a1cb98faSBarry Smith     \   |   /
5941a1cb98faSBarry Smith      \  |  /
5942a1cb98faSBarry Smith       \ | /
5943a1cb98faSBarry Smith         3
5944a1cb98faSBarry Smith .ve
5945a1cb98faSBarry Smith 
5946e1b2f275SBarry Smith   Vertices are implicitly numbered consecutively $0, \ldots, \mathrm{NVertices}$.
5947e1b2f275SBarry Smith 
5948e1b2f275SBarry Smith   Each process owns a chunk of `numVertices` consecutive vertices.
5949e1b2f275SBarry Smith 
5950e1b2f275SBarry Smith   If `numVertices` is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using `PetscLayout`.
5951e1b2f275SBarry Smith 
5952e1b2f275SBarry Smith   If `NVertices` is `PETSC_DETERMINE` and `numVertices` is `PETSC_DECIDE`, `NVertices` is computed by PETSc as the maximum vertex index in $ cells + 1 $.
5953e1b2f275SBarry Smith 
5954e1b2f275SBarry Smith   If only `NVertices` is `PETSC_DETERMINE`, it is computed as the sum of `numVertices` over all processes.
5955a1cb98faSBarry Smith 
5956a1cb98faSBarry Smith   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
5957a1cb98faSBarry Smith 
59581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
5959a1cb98faSBarry Smith           `PetscSF`
5960b09969d6SVaclav Hapla @*/
5961ce78bad3SBarry Smith PetscErrorCode DMPlexBuildFromCellListParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[])
5962d71ae5a4SJacob Faibussowitsch {
59632464107aSksagiyam   PetscSF     sfPoint;
59642464107aSksagiyam   PetscLayout layout;
596582fb893eSVaclav Hapla   PetscInt    numVerticesAdj, *verticesAdj, *cones, c, p;
5966a47d0d45SMatthew G. Knepley 
5967a47d0d45SMatthew G. Knepley   PetscFunctionBegin;
596825b6865aSVaclav Hapla   PetscValidLogicalCollectiveInt(dm, NVertices, 4);
59699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
597025b6865aSVaclav Hapla   /* Get/check global number of vertices */
597125b6865aSVaclav Hapla   {
597225b6865aSVaclav Hapla     PetscInt       NVerticesInCells, i;
597325b6865aSVaclav Hapla     const PetscInt len = numCells * numCorners;
597425b6865aSVaclav Hapla 
597525b6865aSVaclav Hapla     /* NVerticesInCells = max(cells) + 1 */
59761690c2aeSBarry Smith     NVerticesInCells = PETSC_INT_MIN;
59779371c9d4SSatish Balay     for (i = 0; i < len; i++)
59789371c9d4SSatish Balay       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
597925b6865aSVaclav Hapla     ++NVerticesInCells;
5980462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
598125b6865aSVaclav Hapla 
598225b6865aSVaclav Hapla     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
59839371c9d4SSatish Balay     else
59849371c9d4SSatish Balay       PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells);
598525b6865aSVaclav Hapla   }
59869079aca8SVaclav Hapla   /* Count locally unique vertices */
59879079aca8SVaclav Hapla   {
59889079aca8SVaclav Hapla     PetscHSetI vhash;
59899079aca8SVaclav Hapla     PetscInt   off = 0;
59909079aca8SVaclav Hapla 
59919566063dSJacob Faibussowitsch     PetscCall(PetscHSetICreate(&vhash));
5992a47d0d45SMatthew G. Knepley     for (c = 0; c < numCells; ++c) {
599348a46eb9SPierre Jolivet       for (p = 0; p < numCorners; ++p) PetscCall(PetscHSetIAdd(vhash, cells[c * numCorners + p]));
5994a47d0d45SMatthew G. Knepley     }
59959566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
59969566063dSJacob Faibussowitsch     if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
5997ad540459SPierre Jolivet     else verticesAdj = *verticesAdjSaved;
59989566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
59999566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&vhash));
600063a3b9bcSJacob Faibussowitsch     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
6001a47d0d45SMatthew G. Knepley   }
60029566063dSJacob Faibussowitsch   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
6003a47d0d45SMatthew G. Knepley   /* Create cones */
60049566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
60059566063dSJacob Faibussowitsch   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
60069566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
60079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
6008a47d0d45SMatthew G. Knepley   for (c = 0; c < numCells; ++c) {
6009a47d0d45SMatthew G. Knepley     for (p = 0; p < numCorners; ++p) {
6010a47d0d45SMatthew G. Knepley       const PetscInt gv = cells[c * numCorners + p];
6011a47d0d45SMatthew G. Knepley       PetscInt       lv;
6012a47d0d45SMatthew G. Knepley 
60139079aca8SVaclav Hapla       /* Positions within verticesAdj form 0-based local vertex numbering;
60149079aca8SVaclav Hapla          we need to shift it by numCells to get correct DAG points (cells go first) */
60159566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
601663a3b9bcSJacob Faibussowitsch       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
6017961cfab0SVaclav Hapla       cones[c * numCorners + p] = lv + numCells;
6018a47d0d45SMatthew G. Knepley     }
6019a47d0d45SMatthew G. Knepley   }
60202464107aSksagiyam   /* Build point sf */
60219566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
60229566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(layout, NVertices));
60239566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
60249566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(layout, 1));
60259566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
60269566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
60279566063dSJacob Faibussowitsch   if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj));
60289566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
60292464107aSksagiyam   if (dm->sf) {
60302464107aSksagiyam     const char *prefix;
60312464107aSksagiyam 
60329566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
60339566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
60342464107aSksagiyam   }
60359566063dSJacob Faibussowitsch   PetscCall(DMSetPointSF(dm, sfPoint));
60369566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sfPoint));
6037f4f49eeaSPierre Jolivet   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
6038a47d0d45SMatthew G. Knepley   /* Fill in the rest of the topology structure */
60399566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
60409566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
60419566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
60423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6043a47d0d45SMatthew G. Knepley }
6044a47d0d45SMatthew G. Knepley 
6045b0fe842aSMatthew G. Knepley /*@C
6046b0fe842aSMatthew G. Knepley   DMPlexBuildFromCellSectionParallel - Build distributed `DMPLEX` topology from a list of vertices for each cell (common mesh generator output) allowing multiple celltypes
6047b0fe842aSMatthew G. Knepley 
6048b0fe842aSMatthew G. Knepley   Collective; No Fortran Support
6049b0fe842aSMatthew G. Knepley 
6050b0fe842aSMatthew G. Knepley   Input Parameters:
6051b0fe842aSMatthew G. Knepley + dm          - The `DM`
6052b0fe842aSMatthew G. Knepley . numCells    - The number of cells owned by this process
6053b0fe842aSMatthew G. Knepley . numVertices - The number of vertices to be owned by this process, or `PETSC_DECIDE`
6054b0fe842aSMatthew G. Knepley . NVertices   - The global number of vertices, or `PETSC_DETERMINE`
6055b0fe842aSMatthew G. Knepley . cellSection - The `PetscSection` giving the number of vertices for each cell (layout of cells)
6056b0fe842aSMatthew G. Knepley - cells       - An array of the global vertex numbers for each cell
6057b0fe842aSMatthew G. Knepley 
6058b0fe842aSMatthew G. Knepley   Output Parameters:
6059b0fe842aSMatthew G. Knepley + vertexSF         - (Optional) `PetscSF` describing complete vertex ownership
6060b0fe842aSMatthew G. Knepley - verticesAdjSaved - (Optional) vertex adjacency array
6061b0fe842aSMatthew G. Knepley 
6062b0fe842aSMatthew G. Knepley   Level: advanced
6063b0fe842aSMatthew G. Knepley 
6064b0fe842aSMatthew G. Knepley   Notes:
6065b0fe842aSMatthew G. Knepley   A triangle and quadrilateral sharing a face
6066b0fe842aSMatthew G. Knepley .vb
6067b0fe842aSMatthew G. Knepley         2----------3
6068b0fe842aSMatthew G. Knepley       / |          |
6069b0fe842aSMatthew G. Knepley      /  |          |
6070b0fe842aSMatthew G. Knepley     /   |          |
6071b0fe842aSMatthew G. Knepley    0  0 |     1    |
6072b0fe842aSMatthew G. Knepley     \   |          |
6073b0fe842aSMatthew G. Knepley      \  |          |
6074b0fe842aSMatthew G. Knepley       \ |          |
6075b0fe842aSMatthew G. Knepley         1----------4
6076b0fe842aSMatthew G. Knepley .ve
6077b0fe842aSMatthew G. Knepley   would have input
6078b0fe842aSMatthew G. Knepley .vb
6079b0fe842aSMatthew G. Knepley   numCells = 2, numVertices = 5
6080b0fe842aSMatthew G. Knepley   cells = [0 1 2  1 4 3 2]
6081b0fe842aSMatthew G. Knepley .ve
6082b0fe842aSMatthew G. Knepley   which would result in the `DMPLEX`
6083b0fe842aSMatthew G. Knepley .vb
6084b0fe842aSMatthew G. Knepley         4----------5
6085b0fe842aSMatthew G. Knepley       / |          |
6086b0fe842aSMatthew G. Knepley      /  |          |
6087b0fe842aSMatthew G. Knepley     /   |          |
6088b0fe842aSMatthew G. Knepley    2  0 |     1    |
6089b0fe842aSMatthew G. Knepley     \   |          |
6090b0fe842aSMatthew G. Knepley      \  |          |
6091b0fe842aSMatthew G. Knepley       \ |          |
6092b0fe842aSMatthew G. Knepley         3----------6
6093b0fe842aSMatthew G. Knepley .ve
6094b0fe842aSMatthew G. Knepley 
6095b0fe842aSMatthew G. Knepley   Vertices are implicitly numbered consecutively 0,...,NVertices.
6096b0fe842aSMatthew G. Knepley   Each rank owns a chunk of numVertices consecutive vertices.
6097b0fe842aSMatthew G. Knepley   If numVertices is `PETSC_DECIDE`, PETSc will distribute them as evenly as possible using PetscLayout.
6098b0fe842aSMatthew G. Knepley   If NVertices is `PETSC_DETERMINE` and numVertices is PETSC_DECIDE, NVertices is computed by PETSc as the maximum vertex index in cells + 1.
6099b0fe842aSMatthew G. Knepley   If only NVertices is `PETSC_DETERMINE`, it is computed as the sum of numVertices over all ranks.
6100b0fe842aSMatthew G. Knepley 
6101b0fe842aSMatthew G. Knepley   The cell distribution is arbitrary non-overlapping, independent of the vertex distribution.
6102b0fe842aSMatthew G. Knepley 
6103b0fe842aSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexCreateFromCellSectionParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`,
6104b0fe842aSMatthew G. Knepley           `PetscSF`
6105b0fe842aSMatthew G. Knepley @*/
6106ce78bad3SBarry Smith PetscErrorCode DMPlexBuildFromCellSectionParallel(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, const PetscInt cells[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdjSaved[])
6107b0fe842aSMatthew G. Knepley {
6108b0fe842aSMatthew G. Knepley   PetscSF     sfPoint;
6109b0fe842aSMatthew G. Knepley   PetscLayout layout;
6110b0fe842aSMatthew G. Knepley   PetscInt    numVerticesAdj, *verticesAdj, *cones, cStart, cEnd, len;
6111b0fe842aSMatthew G. Knepley 
6112b0fe842aSMatthew G. Knepley   PetscFunctionBegin;
6113b0fe842aSMatthew G. Knepley   PetscValidLogicalCollectiveInt(dm, NVertices, 4);
6114b0fe842aSMatthew G. Knepley   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6115b0fe842aSMatthew G. Knepley   PetscCall(PetscSectionGetChart(cellSection, &cStart, &cEnd));
6116b0fe842aSMatthew G. Knepley   PetscCall(PetscSectionGetStorageSize(cellSection, &len));
6117b0fe842aSMatthew G. Knepley   PetscCheck(cStart == 0 && cEnd == numCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section chart [%" PetscInt_FMT ", %" PetscInt_FMT ") should be [0, %" PetscInt_FMT ")", cStart, cEnd, numCells);
6118b0fe842aSMatthew G. Knepley   /* Get/check global number of vertices */
6119b0fe842aSMatthew G. Knepley   {
6120b0fe842aSMatthew G. Knepley     PetscInt NVerticesInCells;
6121b0fe842aSMatthew G. Knepley 
6122b0fe842aSMatthew G. Knepley     /* NVerticesInCells = max(cells) + 1 */
6123b0fe842aSMatthew G. Knepley     NVerticesInCells = PETSC_MIN_INT;
6124b0fe842aSMatthew G. Knepley     for (PetscInt i = 0; i < len; i++)
6125b0fe842aSMatthew G. Knepley       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
6126b0fe842aSMatthew G. Knepley     ++NVerticesInCells;
6127b0fe842aSMatthew G. Knepley     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &NVerticesInCells, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
6128b0fe842aSMatthew G. Knepley 
6129b0fe842aSMatthew G. Knepley     if (numVertices == PETSC_DECIDE && NVertices == PETSC_DECIDE) NVertices = NVerticesInCells;
6130b0fe842aSMatthew G. Knepley     else
6131b0fe842aSMatthew G. Knepley       PetscCheck(NVertices == PETSC_DECIDE || NVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified global number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, NVertices, NVerticesInCells);
6132b0fe842aSMatthew G. Knepley   }
6133b0fe842aSMatthew G. Knepley   /* Count locally unique vertices */
6134b0fe842aSMatthew G. Knepley   {
6135b0fe842aSMatthew G. Knepley     PetscHSetI vhash;
6136b0fe842aSMatthew G. Knepley     PetscInt   off = 0;
6137b0fe842aSMatthew G. Knepley 
6138b0fe842aSMatthew G. Knepley     PetscCall(PetscHSetICreate(&vhash));
6139b0fe842aSMatthew G. Knepley     for (PetscInt i = 0; i < len; i++) PetscCall(PetscHSetIAdd(vhash, cells[i]));
6140b0fe842aSMatthew G. Knepley     PetscCall(PetscHSetIGetSize(vhash, &numVerticesAdj));
6141b0fe842aSMatthew G. Knepley     if (!verticesAdjSaved) PetscCall(PetscMalloc1(numVerticesAdj, &verticesAdj));
6142b0fe842aSMatthew G. Knepley     else verticesAdj = *verticesAdjSaved;
6143b0fe842aSMatthew G. Knepley     PetscCall(PetscHSetIGetElems(vhash, &off, verticesAdj));
6144b0fe842aSMatthew G. Knepley     PetscCall(PetscHSetIDestroy(&vhash));
6145b0fe842aSMatthew G. Knepley     PetscCheck(off == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of local vertices %" PetscInt_FMT " should be %" PetscInt_FMT, off, numVerticesAdj);
6146b0fe842aSMatthew G. Knepley   }
6147b0fe842aSMatthew G. Knepley   PetscCall(PetscSortInt(numVerticesAdj, verticesAdj));
6148b0fe842aSMatthew G. Knepley   /* Create cones */
6149b0fe842aSMatthew G. Knepley   PetscCall(DMPlexSetChart(dm, 0, numCells + numVerticesAdj));
6150b0fe842aSMatthew G. Knepley   for (PetscInt c = 0; c < numCells; ++c) {
6151b0fe842aSMatthew G. Knepley     PetscInt dof;
6152b0fe842aSMatthew G. Knepley 
6153b0fe842aSMatthew G. Knepley     PetscCall(PetscSectionGetDof(cellSection, c, &dof));
6154b0fe842aSMatthew G. Knepley     PetscCall(DMPlexSetConeSize(dm, c, dof));
6155b0fe842aSMatthew G. Knepley   }
6156b0fe842aSMatthew G. Knepley   PetscCall(DMSetUp(dm));
6157b0fe842aSMatthew G. Knepley   PetscCall(DMPlexGetCones(dm, &cones));
6158b0fe842aSMatthew G. Knepley   for (PetscInt c = 0; c < numCells; ++c) {
6159b0fe842aSMatthew G. Knepley     PetscInt dof, off;
6160b0fe842aSMatthew G. Knepley 
6161b0fe842aSMatthew G. Knepley     PetscCall(PetscSectionGetDof(cellSection, c, &dof));
6162b0fe842aSMatthew G. Knepley     PetscCall(PetscSectionGetOffset(cellSection, c, &off));
6163b0fe842aSMatthew G. Knepley     for (PetscInt p = off; p < off + dof; ++p) {
6164b0fe842aSMatthew G. Knepley       const PetscInt gv = cells[p];
6165b0fe842aSMatthew G. Knepley       PetscInt       lv;
6166b0fe842aSMatthew G. Knepley 
6167b0fe842aSMatthew G. Knepley       /* Positions within verticesAdj form 0-based local vertex numbering;
6168b0fe842aSMatthew G. Knepley          we need to shift it by numCells to get correct DAG points (cells go first) */
6169b0fe842aSMatthew G. Knepley       PetscCall(PetscFindInt(gv, numVerticesAdj, verticesAdj, &lv));
6170b0fe842aSMatthew G. Knepley       PetscCheck(lv >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not find global vertex %" PetscInt_FMT " in local connectivity", gv);
6171b0fe842aSMatthew G. Knepley       cones[p] = lv + numCells;
6172b0fe842aSMatthew G. Knepley     }
6173b0fe842aSMatthew G. Knepley   }
6174b0fe842aSMatthew G. Knepley   /* Build point sf */
6175b0fe842aSMatthew G. Knepley   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &layout));
6176b0fe842aSMatthew G. Knepley   PetscCall(PetscLayoutSetSize(layout, NVertices));
6177b0fe842aSMatthew G. Knepley   PetscCall(PetscLayoutSetLocalSize(layout, numVertices));
6178b0fe842aSMatthew G. Knepley   PetscCall(PetscLayoutSetBlockSize(layout, 1));
6179b0fe842aSMatthew G. Knepley   PetscCall(PetscSFCreateByMatchingIndices(layout, numVerticesAdj, verticesAdj, NULL, numCells, numVerticesAdj, verticesAdj, NULL, numCells, vertexSF, &sfPoint));
6180b0fe842aSMatthew G. Knepley   PetscCall(PetscLayoutDestroy(&layout));
6181b0fe842aSMatthew G. Knepley   if (!verticesAdjSaved) PetscCall(PetscFree(verticesAdj));
6182b0fe842aSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)sfPoint, "point SF"));
6183b0fe842aSMatthew G. Knepley   if (dm->sf) {
6184b0fe842aSMatthew G. Knepley     const char *prefix;
6185b0fe842aSMatthew G. Knepley 
6186b0fe842aSMatthew G. Knepley     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm->sf, &prefix));
6187b0fe842aSMatthew G. Knepley     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)sfPoint, prefix));
6188b0fe842aSMatthew G. Knepley   }
6189b0fe842aSMatthew G. Knepley   PetscCall(DMSetPointSF(dm, sfPoint));
6190b0fe842aSMatthew G. Knepley   PetscCall(PetscSFDestroy(&sfPoint));
6191b0fe842aSMatthew G. Knepley   if (vertexSF) PetscCall(PetscObjectSetName((PetscObject)*vertexSF, "Vertex Ownership SF"));
6192b0fe842aSMatthew G. Knepley   /* Fill in the rest of the topology structure */
6193b0fe842aSMatthew G. Knepley   PetscCall(DMPlexSymmetrize(dm));
6194b0fe842aSMatthew G. Knepley   PetscCall(DMPlexStratify(dm));
6195b0fe842aSMatthew G. Knepley   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
6196b0fe842aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
6197b0fe842aSMatthew G. Knepley }
6198b0fe842aSMatthew G. Knepley 
6199cc4c1da9SBarry Smith /*@
6200a1cb98faSBarry Smith   DMPlexBuildCoordinatesFromCellListParallel - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
6201a1cb98faSBarry Smith 
620220f4b53cSBarry Smith   Collective; No Fortran Support
6203b09969d6SVaclav Hapla 
6204b09969d6SVaclav Hapla   Input Parameters:
6205a1cb98faSBarry Smith + dm           - The `DM`
6206b09969d6SVaclav Hapla . spaceDim     - The spatial dimension used for coordinates
6207a1cb98faSBarry Smith . sfVert       - `PetscSF` describing complete vertex ownership
6208b09969d6SVaclav Hapla - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6209b09969d6SVaclav Hapla 
6210b09969d6SVaclav Hapla   Level: advanced
6211b09969d6SVaclav Hapla 
62121cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellListParallel()`
6213b09969d6SVaclav Hapla @*/
6214d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBuildCoordinatesFromCellListParallel(DM dm, PetscInt spaceDim, PetscSF sfVert, const PetscReal vertexCoords[])
6215d71ae5a4SJacob Faibussowitsch {
6216a47d0d45SMatthew G. Knepley   PetscSection coordSection;
6217a47d0d45SMatthew G. Knepley   Vec          coordinates;
6218a47d0d45SMatthew G. Knepley   PetscScalar *coords;
62191edcf0b2SVaclav Hapla   PetscInt     numVertices, numVerticesAdj, coordSize, v, vStart, vEnd;
6220835f2295SStefano Zampini   PetscMPIInt  spaceDimi;
6221a47d0d45SMatthew G. Knepley 
6222a47d0d45SMatthew G. Knepley   PetscFunctionBegin;
62239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
62249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
62251dca8a05SBarry Smith   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
62269566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, spaceDim));
62279566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfVert, &numVertices, &numVerticesAdj, NULL, NULL));
62281dca8a05SBarry Smith   PetscCheck(vEnd - vStart == numVerticesAdj, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Supplied sfVert has wrong number of leaves = %" PetscInt_FMT " != %" PetscInt_FMT " = vEnd - vStart", numVerticesAdj, vEnd - vStart);
62299566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
62309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
62319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
62329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
62331edcf0b2SVaclav Hapla   for (v = vStart; v < vEnd; ++v) {
62349566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
62359566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
6236a47d0d45SMatthew G. Knepley   }
62379566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
62389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
62399566063dSJacob Faibussowitsch   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), &coordinates));
62409566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, spaceDim));
62419566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
62429566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
62439566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
62449566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
6245a47d0d45SMatthew G. Knepley   {
6246a47d0d45SMatthew G. Knepley     MPI_Datatype coordtype;
6247a47d0d45SMatthew G. Knepley 
6248a47d0d45SMatthew G. Knepley     /* Need a temp buffer for coords if we have complex/single */
6249835f2295SStefano Zampini     PetscCall(PetscMPIIntCast(spaceDim, &spaceDimi));
6250835f2295SStefano Zampini     PetscCallMPI(MPI_Type_contiguous(spaceDimi, MPIU_SCALAR, &coordtype));
62519566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&coordtype));
625221016a8bSBarry Smith #if defined(PETSC_USE_COMPLEX)
625321016a8bSBarry Smith     {
625421016a8bSBarry Smith       PetscScalar *svertexCoords;
625521016a8bSBarry Smith       PetscInt     i;
62569566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numVertices * spaceDim, &svertexCoords));
62573612f820SVaclav Hapla       for (i = 0; i < numVertices * spaceDim; i++) svertexCoords[i] = vertexCoords[i];
62589566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
62599566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sfVert, coordtype, svertexCoords, coords, MPI_REPLACE));
62609566063dSJacob Faibussowitsch       PetscCall(PetscFree(svertexCoords));
626121016a8bSBarry Smith     }
626221016a8bSBarry Smith #else
62639566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
62649566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sfVert, coordtype, vertexCoords, coords, MPI_REPLACE));
626521016a8bSBarry Smith #endif
62669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&coordtype));
6267a47d0d45SMatthew G. Knepley   }
62689566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
62699566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
62709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
62719566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
62723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6273a47d0d45SMatthew G. Knepley }
6274a47d0d45SMatthew G. Knepley 
6275c3edce3dSSatish Balay /*@
6276b0fe842aSMatthew G. Knepley   DMPlexCreateFromCellListParallelPetsc - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) where all cells have the same celltype
6277a1cb98faSBarry Smith 
6278a1cb98faSBarry Smith   Collective
6279a47d0d45SMatthew G. Knepley 
6280a47d0d45SMatthew G. Knepley   Input Parameters:
6281a47d0d45SMatthew G. Knepley + comm         - The communicator
6282a47d0d45SMatthew G. Knepley . dim          - The topological dimension of the mesh
6283a47d0d45SMatthew G. Knepley . numCells     - The number of cells owned by this process
6284a1cb98faSBarry Smith . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
6285a1cb98faSBarry Smith . NVertices    - The global number of vertices, or `PETSC_DECIDE`
6286a47d0d45SMatthew G. Knepley . numCorners   - The number of vertices for each cell
6287a47d0d45SMatthew G. Knepley . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6288a47d0d45SMatthew G. Knepley . cells        - An array of numCells*numCorners numbers, the global vertex numbers for each cell
6289a47d0d45SMatthew G. Knepley . spaceDim     - The spatial dimension used for coordinates
6290a47d0d45SMatthew G. Knepley - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6291a47d0d45SMatthew G. Knepley 
6292d8d19677SJose E. Roman   Output Parameters:
6293a1cb98faSBarry Smith + dm          - The `DM`
6294a1cb98faSBarry Smith . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
629560225df5SJacob Faibussowitsch - verticesAdj - (Optional) vertex adjacency array
6296a47d0d45SMatthew G. Knepley 
6297b09969d6SVaclav Hapla   Level: intermediate
6298a47d0d45SMatthew G. Knepley 
6299a1cb98faSBarry Smith   Notes:
6300a1cb98faSBarry Smith   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
6301a1cb98faSBarry Smith   `DMPlexBuildFromCellListParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`
6302a1cb98faSBarry Smith 
6303a1cb98faSBarry Smith   See `DMPlexBuildFromCellListParallel()` for an example and details about the topology-related parameters.
6304a1cb98faSBarry Smith 
6305a1cb98faSBarry Smith   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.
6306a1cb98faSBarry Smith 
63071cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
6308a47d0d45SMatthew G. Knepley @*/
6309ce78bad3SBarry Smith PetscErrorCode DMPlexCreateFromCellListParallelPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm)
6310d71ae5a4SJacob Faibussowitsch {
6311a47d0d45SMatthew G. Knepley   PetscSF sfVert;
6312a47d0d45SMatthew G. Knepley 
6313a47d0d45SMatthew G. Knepley   PetscFunctionBegin;
63149566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
63159566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
6316a47d0d45SMatthew G. Knepley   PetscValidLogicalCollectiveInt(*dm, dim, 2);
6317064a246eSJacob Faibussowitsch   PetscValidLogicalCollectiveInt(*dm, spaceDim, 9);
63189566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*dm, dim));
63199566063dSJacob Faibussowitsch   PetscCall(DMPlexBuildFromCellListParallel(*dm, numCells, numVertices, NVertices, numCorners, cells, &sfVert, verticesAdj));
6320a47d0d45SMatthew G. Knepley   if (interpolate) {
63215fd9971aSMatthew G. Knepley     DM idm;
6322a47d0d45SMatthew G. Knepley 
63239566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
63249566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
6325a47d0d45SMatthew G. Knepley     *dm = idm;
6326a47d0d45SMatthew G. Knepley   }
63279566063dSJacob Faibussowitsch   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
632818d54ad4SMichael Lange   if (vertexSF) *vertexSF = sfVert;
63299566063dSJacob Faibussowitsch   else PetscCall(PetscSFDestroy(&sfVert));
63303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6331a47d0d45SMatthew G. Knepley }
6332a47d0d45SMatthew G. Knepley 
6333cc4c1da9SBarry Smith /*@
6334b0fe842aSMatthew G. Knepley   DMPlexCreateFromCellSectionParallel - Create distributed `DMPLEX` from a list of vertices for each cell (common mesh generator output) and supports multiple celltypes
6335b0fe842aSMatthew G. Knepley 
6336b0fe842aSMatthew G. Knepley   Collective
6337b0fe842aSMatthew G. Knepley 
6338b0fe842aSMatthew G. Knepley   Input Parameters:
6339b0fe842aSMatthew G. Knepley + comm         - The communicator
6340b0fe842aSMatthew G. Knepley . dim          - The topological dimension of the mesh
6341b0fe842aSMatthew G. Knepley . numCells     - The number of cells owned by this process
6342b0fe842aSMatthew G. Knepley . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`
6343b0fe842aSMatthew G. Knepley . NVertices    - The global number of vertices, or `PETSC_DECIDE`
6344b0fe842aSMatthew G. Knepley . cellSection  - The `PetscSection` giving the number of vertices for each cell (layout of cells)
6345b0fe842aSMatthew G. Knepley . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6346b0fe842aSMatthew G. Knepley . cells        - An array of the global vertex numbers for each cell
6347b0fe842aSMatthew G. Knepley . spaceDim     - The spatial dimension used for coordinates
6348b0fe842aSMatthew G. Knepley - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6349b0fe842aSMatthew G. Knepley 
6350b0fe842aSMatthew G. Knepley   Output Parameters:
6351b0fe842aSMatthew G. Knepley + dm          - The `DM`
6352b0fe842aSMatthew G. Knepley . vertexSF    - (Optional) `PetscSF` describing complete vertex ownership
6353b0fe842aSMatthew G. Knepley - verticesAdj - (Optional) vertex adjacency array
6354b0fe842aSMatthew G. Knepley 
6355b0fe842aSMatthew G. Knepley   Level: intermediate
6356b0fe842aSMatthew G. Knepley 
6357b0fe842aSMatthew G. Knepley   Notes:
6358b0fe842aSMatthew G. Knepley   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`,
6359b0fe842aSMatthew G. Knepley   `DMPlexBuildFromCellSectionParallel()`, `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellListParallel()`
6360b0fe842aSMatthew G. Knepley 
6361b0fe842aSMatthew G. Knepley   See `DMPlexBuildFromCellSectionParallel()` for an example and details about the topology-related parameters.
6362b0fe842aSMatthew G. Knepley 
6363b0fe842aSMatthew G. Knepley   See `DMPlexBuildCoordinatesFromCellListParallel()` for details about the geometry-related parameters.
6364b0fe842aSMatthew G. Knepley 
6365b0fe842aSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
6366b0fe842aSMatthew G. Knepley @*/
6367ce78bad3SBarry Smith PetscErrorCode DMPlexCreateFromCellSectionParallel(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt NVertices, PetscSection cellSection, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], PeOp PetscSF *vertexSF, PeOp PetscInt *verticesAdj[], DM *dm)
6368b0fe842aSMatthew G. Knepley {
6369b0fe842aSMatthew G. Knepley   PetscSF sfVert;
6370b0fe842aSMatthew G. Knepley 
6371b0fe842aSMatthew G. Knepley   PetscFunctionBegin;
6372b0fe842aSMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
6373b0fe842aSMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
6374b0fe842aSMatthew G. Knepley   PetscValidLogicalCollectiveInt(*dm, dim, 2);
6375b0fe842aSMatthew G. Knepley   PetscValidLogicalCollectiveInt(*dm, spaceDim, 9);
6376b0fe842aSMatthew G. Knepley   PetscCall(DMSetDimension(*dm, dim));
6377b0fe842aSMatthew G. Knepley   PetscCall(DMPlexBuildFromCellSectionParallel(*dm, numCells, numVertices, NVertices, cellSection, cells, &sfVert, verticesAdj));
6378b0fe842aSMatthew G. Knepley   if (interpolate) {
6379b0fe842aSMatthew G. Knepley     DM idm;
6380b0fe842aSMatthew G. Knepley 
6381b0fe842aSMatthew G. Knepley     PetscCall(DMPlexInterpolate(*dm, &idm));
6382b0fe842aSMatthew G. Knepley     PetscCall(DMDestroy(dm));
6383b0fe842aSMatthew G. Knepley     *dm = idm;
6384b0fe842aSMatthew G. Knepley   }
6385b0fe842aSMatthew G. Knepley   PetscCall(DMPlexBuildCoordinatesFromCellListParallel(*dm, spaceDim, sfVert, vertexCoords));
6386b0fe842aSMatthew G. Knepley   if (vertexSF) *vertexSF = sfVert;
6387b0fe842aSMatthew G. Knepley   else PetscCall(PetscSFDestroy(&sfVert));
6388b0fe842aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
6389b0fe842aSMatthew G. Knepley }
6390b0fe842aSMatthew G. Knepley 
6391b0fe842aSMatthew G. Knepley /*@
6392a1cb98faSBarry Smith   DMPlexBuildFromCellList - Build `DMPLEX` topology from a list of vertices for each cell (common mesh generator output)
6393a1cb98faSBarry Smith 
639420f4b53cSBarry Smith   Collective; No Fortran Support
63959298eaa6SMatthew G Knepley 
63969298eaa6SMatthew G Knepley   Input Parameters:
6397a1cb98faSBarry Smith + dm          - The `DM`
6398b09969d6SVaclav Hapla . numCells    - The number of cells owned by this process
6399a1cb98faSBarry Smith . numVertices - The number of vertices owned by this process, or `PETSC_DETERMINE`
64009298eaa6SMatthew G Knepley . numCorners  - The number of vertices for each cell
6401a3b724e8SBarry Smith - cells       - An array of `numCells` x `numCorners` numbers, the global vertex numbers for each cell
64029298eaa6SMatthew G Knepley 
6403b09969d6SVaclav Hapla   Level: advanced
64049298eaa6SMatthew G Knepley 
6405b09969d6SVaclav Hapla   Notes:
6406b09969d6SVaclav Hapla   Two triangles sharing a face
6407a1cb98faSBarry Smith .vb
64089298eaa6SMatthew G Knepley 
6409a1cb98faSBarry Smith         2
6410a1cb98faSBarry Smith       / | \
6411a1cb98faSBarry Smith      /  |  \
6412a1cb98faSBarry Smith     /   |   \
6413a1cb98faSBarry Smith    0  0 | 1  3
6414a1cb98faSBarry Smith     \   |   /
6415a1cb98faSBarry Smith      \  |  /
6416a1cb98faSBarry Smith       \ | /
6417a1cb98faSBarry Smith         1
6418a1cb98faSBarry Smith .ve
6419a1cb98faSBarry Smith   would have input
6420a1cb98faSBarry Smith .vb
6421a1cb98faSBarry Smith   numCells = 2, numVertices = 4
6422a1cb98faSBarry Smith   cells = [0 1 2  1 3 2]
6423a1cb98faSBarry Smith .ve
6424a1cb98faSBarry Smith   which would result in the `DMPLEX`
6425a1cb98faSBarry Smith .vb
6426a1cb98faSBarry Smith 
6427a1cb98faSBarry Smith         4
6428a1cb98faSBarry Smith       / | \
6429a1cb98faSBarry Smith      /  |  \
6430a1cb98faSBarry Smith     /   |   \
6431a1cb98faSBarry Smith    2  0 | 1  5
6432a1cb98faSBarry Smith     \   |   /
6433a1cb98faSBarry Smith      \  |  /
6434a1cb98faSBarry Smith       \ | /
6435a1cb98faSBarry Smith         3
6436a1cb98faSBarry Smith .ve
6437a1cb98faSBarry Smith 
6438a1cb98faSBarry Smith   If numVertices is `PETSC_DETERMINE`, it is computed by PETSc as the maximum vertex index in cells + 1.
643925b6865aSVaclav Hapla 
64401cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildFromCellListParallel()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromCellListPetsc()`
6441b09969d6SVaclav Hapla @*/
6442d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBuildFromCellList(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const PetscInt cells[])
6443d71ae5a4SJacob Faibussowitsch {
6444961cfab0SVaclav Hapla   PetscInt *cones, c, p, dim;
6445b09969d6SVaclav Hapla 
6446b09969d6SVaclav Hapla   PetscFunctionBegin;
64479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
64489566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
644925b6865aSVaclav Hapla   /* Get/check global number of vertices */
645025b6865aSVaclav Hapla   {
645125b6865aSVaclav Hapla     PetscInt       NVerticesInCells, i;
645225b6865aSVaclav Hapla     const PetscInt len = numCells * numCorners;
645325b6865aSVaclav Hapla 
645425b6865aSVaclav Hapla     /* NVerticesInCells = max(cells) + 1 */
64551690c2aeSBarry Smith     NVerticesInCells = PETSC_INT_MIN;
64569371c9d4SSatish Balay     for (i = 0; i < len; i++)
64579371c9d4SSatish Balay       if (cells[i] > NVerticesInCells) NVerticesInCells = cells[i];
645825b6865aSVaclav Hapla     ++NVerticesInCells;
645925b6865aSVaclav Hapla 
646025b6865aSVaclav Hapla     if (numVertices == PETSC_DECIDE) numVertices = NVerticesInCells;
64619371c9d4SSatish Balay     else
64629371c9d4SSatish Balay       PetscCheck(numVertices >= NVerticesInCells, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Specified number of vertices %" PetscInt_FMT " must be greater than or equal to the number of vertices in cells %" PetscInt_FMT, numVertices, NVerticesInCells);
646325b6865aSVaclav Hapla   }
64649566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(dm, 0, numCells + numVertices));
646548a46eb9SPierre Jolivet   for (c = 0; c < numCells; ++c) PetscCall(DMPlexSetConeSize(dm, c, numCorners));
64669566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
64679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCones(dm, &cones));
6468b09969d6SVaclav Hapla   for (c = 0; c < numCells; ++c) {
6469ad540459SPierre Jolivet     for (p = 0; p < numCorners; ++p) cones[c * numCorners + p] = cells[c * numCorners + p] + numCells;
6470b09969d6SVaclav Hapla   }
64719566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
64729566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
64739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_BuildFromCellList, dm, 0, 0, 0));
64743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6475b09969d6SVaclav Hapla }
6476b09969d6SVaclav Hapla 
6477cc4c1da9SBarry Smith /*@
6478a1cb98faSBarry Smith   DMPlexBuildCoordinatesFromCellList - Build `DM` coordinates from a list of coordinates for each owned vertex (common mesh generator output)
6479a1cb98faSBarry Smith 
6480cc4c1da9SBarry Smith   Collective
6481b09969d6SVaclav Hapla 
6482b09969d6SVaclav Hapla   Input Parameters:
6483a1cb98faSBarry Smith + dm           - The `DM`
6484b09969d6SVaclav Hapla . spaceDim     - The spatial dimension used for coordinates
6485b09969d6SVaclav Hapla - vertexCoords - An array of numVertices*spaceDim numbers, the coordinates of each vertex
6486b09969d6SVaclav Hapla 
6487b09969d6SVaclav Hapla   Level: advanced
6488b09969d6SVaclav Hapla 
64891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexBuildCoordinatesFromCellListParallel()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexBuildFromCellList()`
6490b09969d6SVaclav Hapla @*/
6491d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBuildCoordinatesFromCellList(DM dm, PetscInt spaceDim, const PetscReal vertexCoords[])
6492d71ae5a4SJacob Faibussowitsch {
6493b09969d6SVaclav Hapla   PetscSection coordSection;
6494b09969d6SVaclav Hapla   Vec          coordinates;
6495b09969d6SVaclav Hapla   DM           cdm;
6496b09969d6SVaclav Hapla   PetscScalar *coords;
64971edcf0b2SVaclav Hapla   PetscInt     v, vStart, vEnd, d;
6498b09969d6SVaclav Hapla 
6499b09969d6SVaclav Hapla   PetscFunctionBegin;
65009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
65019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
65021dca8a05SBarry Smith   PetscCheck(vStart >= 0 && vEnd >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not set up properly. DMPlexBuildFromCellList() should be called first.");
65039566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(dm, spaceDim));
65049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
65059566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
65069566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, spaceDim));
65079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, vStart, vEnd));
65081edcf0b2SVaclav Hapla   for (v = vStart; v < vEnd; ++v) {
65099566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, spaceDim));
65109566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, spaceDim));
6511b09969d6SVaclav Hapla   }
65129566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
6513b09969d6SVaclav Hapla 
65149566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(dm, &cdm));
65159566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector(cdm, &coordinates));
65169566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, spaceDim));
65179566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
65189566063dSJacob Faibussowitsch   PetscCall(VecGetArrayWrite(coordinates, &coords));
65191edcf0b2SVaclav Hapla   for (v = 0; v < vEnd - vStart; ++v) {
6520ad540459SPierre Jolivet     for (d = 0; d < spaceDim; ++d) coords[v * spaceDim + d] = vertexCoords[v * spaceDim + d];
6521b09969d6SVaclav Hapla   }
65229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayWrite(coordinates, &coords));
65239566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
65249566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
65259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_BuildCoordinatesFromCellList, dm, 0, 0, 0));
65263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6527b09969d6SVaclav Hapla }
6528b09969d6SVaclav Hapla 
6529b09969d6SVaclav Hapla /*@
6530a1cb98faSBarry Smith   DMPlexCreateFromCellListPetsc - Create `DMPLEX` from a list of vertices for each cell (common mesh generator output), but only process 0 takes in the input
65313df08285SMatthew G. Knepley 
6532a1cb98faSBarry Smith   Collective
6533b09969d6SVaclav Hapla 
6534b09969d6SVaclav Hapla   Input Parameters:
6535b09969d6SVaclav Hapla + comm         - The communicator
6536b09969d6SVaclav Hapla . dim          - The topological dimension of the mesh
65373df08285SMatthew G. Knepley . numCells     - The number of cells, only on process 0
6538a1cb98faSBarry Smith . numVertices  - The number of vertices owned by this process, or `PETSC_DECIDE`, only on process 0
65393df08285SMatthew G. Knepley . numCorners   - The number of vertices for each cell, only on process 0
6540b09969d6SVaclav Hapla . interpolate  - Flag indicating that intermediate mesh entities (faces, edges) should be created automatically
6541ce78bad3SBarry Smith . cells        - An array of $ numCells \times numCorners$ numbers, the vertices for each cell, only on process 0
6542b09969d6SVaclav Hapla . spaceDim     - The spatial dimension used for coordinates
6543ce78bad3SBarry Smith - vertexCoords - An array of $ numVertices \times spaceDim$ numbers, the coordinates of each vertex, only on process 0
6544b09969d6SVaclav Hapla 
6545b09969d6SVaclav Hapla   Output Parameter:
6546a1cb98faSBarry Smith . dm - The `DM`, which only has points on process 0
654725b6865aSVaclav Hapla 
6548b09969d6SVaclav Hapla   Level: intermediate
6549b09969d6SVaclav Hapla 
6550a1cb98faSBarry Smith   Notes:
6551a1cb98faSBarry Smith   This function is just a convenient sequence of `DMCreate()`, `DMSetType()`, `DMSetDimension()`, `DMPlexBuildFromCellList()`,
6552a1cb98faSBarry Smith   `DMPlexInterpolate()`, `DMPlexBuildCoordinatesFromCellList()`
6553a1cb98faSBarry Smith 
6554a1cb98faSBarry Smith   See `DMPlexBuildFromCellList()` for an example and details about the topology-related parameters.
6555a1cb98faSBarry Smith   See `DMPlexBuildCoordinatesFromCellList()` for details about the geometry-related parameters.
6556a1cb98faSBarry Smith   See `DMPlexCreateFromCellListParallelPetsc()` for parallel input
6557a1cb98faSBarry Smith 
65581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListParallelPetsc()`, `DMPlexBuildFromCellList()`, `DMPlexBuildCoordinatesFromCellList()`, `DMPlexCreateFromDAG()`, `DMPlexCreate()`
65599298eaa6SMatthew G Knepley @*/
6560d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateFromCellListPetsc(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const PetscInt cells[], PetscInt spaceDim, const PetscReal vertexCoords[], DM *dm)
6561d71ae5a4SJacob Faibussowitsch {
65623df08285SMatthew G. Knepley   PetscMPIInt rank;
65639298eaa6SMatthew G Knepley 
65649298eaa6SMatthew G Knepley   PetscFunctionBegin;
656528b400f6SJacob Faibussowitsch   PetscCheck(dim, comm, PETSC_ERR_ARG_OUTOFRANGE, "This is not appropriate for 0-dimensional meshes. Consider either creating the DM using DMPlexCreateFromDAG(), by hand, or using DMSwarm.");
65669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
65679566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
65689566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
65699566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*dm, dim));
6570c5853193SPierre Jolivet   if (rank == 0) PetscCall(DMPlexBuildFromCellList(*dm, numCells, numVertices, numCorners, cells));
65719566063dSJacob Faibussowitsch   else PetscCall(DMPlexBuildFromCellList(*dm, 0, 0, 0, NULL));
65729298eaa6SMatthew G Knepley   if (interpolate) {
65735fd9971aSMatthew G. Knepley     DM idm;
65749298eaa6SMatthew G Knepley 
65759566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
65769566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
65779298eaa6SMatthew G Knepley     *dm = idm;
65789298eaa6SMatthew G Knepley   }
6579c5853193SPierre Jolivet   if (rank == 0) PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, vertexCoords));
65809566063dSJacob Faibussowitsch   else PetscCall(DMPlexBuildCoordinatesFromCellList(*dm, spaceDim, NULL));
65813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
65829298eaa6SMatthew G Knepley }
65839298eaa6SMatthew G Knepley 
6584939f6067SMatthew G. Knepley /*@
658520f4b53cSBarry Smith   DMPlexCreateFromDAG - This takes as input the adjacency-list representation of the Directed Acyclic Graph (Hasse Diagram) encoding a mesh, and produces a `DM`
6586939f6067SMatthew G. Knepley 
6587939f6067SMatthew G. Knepley   Input Parameters:
658820f4b53cSBarry Smith + dm               - The empty `DM` object, usually from `DMCreate()` and `DMSetDimension()`
6589939f6067SMatthew G. Knepley . depth            - The depth of the DAG
6590ce78bad3SBarry Smith . numPoints        - Array of size $ depth + 1 $ containing the number of points at each `depth`
6591939f6067SMatthew G. Knepley . coneSize         - The cone size of each point
6592939f6067SMatthew G. Knepley . cones            - The concatenation of the cone points for each point, the cone list must be oriented correctly for each point
6593939f6067SMatthew G. Knepley . coneOrientations - The orientation of each cone point
6594ce78bad3SBarry Smith - vertexCoords     - An array of $ numPoints[0] \times spacedim $ numbers representing the coordinates of each vertex, with `spacedim` the value set via `DMSetCoordinateDim()`
6595939f6067SMatthew G. Knepley 
6596939f6067SMatthew G. Knepley   Output Parameter:
659720f4b53cSBarry Smith . dm - The `DM`
659820f4b53cSBarry Smith 
659920f4b53cSBarry Smith   Level: advanced
6600939f6067SMatthew G. Knepley 
6601a1cb98faSBarry Smith   Note:
6602a1cb98faSBarry Smith   Two triangles sharing a face would have input
6603a1cb98faSBarry Smith .vb
6604a1cb98faSBarry Smith   depth = 1, numPoints = [4 2], coneSize = [3 3 0 0 0 0]
6605a1cb98faSBarry Smith   cones = [2 3 4  3 5 4], coneOrientations = [0 0 0  0 0 0]
6606a1cb98faSBarry Smith  vertexCoords = [-1.0 0.0  0.0 -1.0  0.0 1.0  1.0 0.0]
6607a1cb98faSBarry Smith .ve
6608939f6067SMatthew G. Knepley   which would result in the DMPlex
6609a1cb98faSBarry Smith .vb
6610a1cb98faSBarry Smith         4
6611a1cb98faSBarry Smith       / | \
6612a1cb98faSBarry Smith      /  |  \
6613a1cb98faSBarry Smith     /   |   \
6614a1cb98faSBarry Smith    2  0 | 1  5
6615a1cb98faSBarry Smith     \   |   /
6616a1cb98faSBarry Smith      \  |  /
6617a1cb98faSBarry Smith       \ | /
6618a1cb98faSBarry Smith         3
6619a1cb98faSBarry Smith .ve
6620a1cb98faSBarry Smith   Notice that all points are numbered consecutively, unlike `DMPlexCreateFromCellListPetsc()`
6621939f6067SMatthew G. Knepley 
6622ce78bad3SBarry Smith   Developer Note:
6623ce78bad3SBarry Smith   This does not create anything so should not have create in the name.
6624ce78bad3SBarry Smith 
66251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
6626939f6067SMatthew G. Knepley @*/
6627d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
6628d71ae5a4SJacob Faibussowitsch {
66299298eaa6SMatthew G Knepley   Vec          coordinates;
66309298eaa6SMatthew G Knepley   PetscSection coordSection;
66319298eaa6SMatthew G Knepley   PetscScalar *coords;
6632811e8653SToby Isaac   PetscInt     coordSize, firstVertex = -1, pStart = 0, pEnd = 0, p, v, dim, dimEmbed, d, off;
66339298eaa6SMatthew G Knepley 
66349298eaa6SMatthew G Knepley   PetscFunctionBegin;
66359566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
66369566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
663763a3b9bcSJacob Faibussowitsch   PetscCheck(dimEmbed >= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Embedding dimension %" PetscInt_FMT " cannot be less than intrinsic dimension %" PetscInt_FMT, dimEmbed, dim);
66389298eaa6SMatthew G Knepley   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
66399566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(dm, pStart, pEnd));
66409298eaa6SMatthew G Knepley   for (p = pStart; p < pEnd; ++p) {
66419566063dSJacob Faibussowitsch     PetscCall(DMPlexSetConeSize(dm, p, coneSize[p - pStart]));
6642ad540459SPierre Jolivet     if (firstVertex < 0 && !coneSize[p - pStart]) firstVertex = p - pStart;
664397e052ccSToby Isaac   }
66441dca8a05SBarry Smith   PetscCheck(firstVertex >= 0 || !numPoints[0], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected %" PetscInt_FMT " vertices but could not find any", numPoints[0]);
66459566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm)); /* Allocate space for cones */
66469298eaa6SMatthew G Knepley   for (p = pStart, off = 0; p < pEnd; off += coneSize[p - pStart], ++p) {
66479566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCone(dm, p, &cones[off]));
66489566063dSJacob Faibussowitsch     PetscCall(DMPlexSetConeOrientation(dm, p, &coneOrientations[off]));
66499298eaa6SMatthew G Knepley   }
66509566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(dm));
66519566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(dm));
66529298eaa6SMatthew G Knepley   /* Build coordinates */
66539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(dm, &coordSection));
66549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
66559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, dimEmbed));
66569566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, firstVertex, firstVertex + numPoints[0]));
66579298eaa6SMatthew G Knepley   for (v = firstVertex; v < firstVertex + numPoints[0]; ++v) {
66589566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, dimEmbed));
66599566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, dimEmbed));
66609298eaa6SMatthew G Knepley   }
66619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
66629566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
66639566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
66649566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
66659566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
666658b7e2c1SStefano Zampini   PetscCall(VecSetBlockSize(coordinates, PetscMax(dimEmbed, 1)));
66679566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
66689318fe57SMatthew G. Knepley   if (vertexCoords) {
66699566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &coords));
66709298eaa6SMatthew G Knepley     for (v = 0; v < numPoints[0]; ++v) {
66719298eaa6SMatthew G Knepley       PetscInt off;
66729298eaa6SMatthew G Knepley 
66739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSection, v + firstVertex, &off));
6674ad540459SPierre Jolivet       for (d = 0; d < dimEmbed; ++d) coords[off + d] = vertexCoords[v * dimEmbed + d];
66759298eaa6SMatthew G Knepley     }
66769318fe57SMatthew G. Knepley   }
66779566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
66789566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
66799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
66803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
66819298eaa6SMatthew G Knepley }
66828415267dSToby Isaac 
6683a4e35b19SJacob Faibussowitsch /*
6684a1cb98faSBarry Smith   DMPlexCreateCellVertexFromFile - Create a `DMPLEX` mesh from a simple cell-vertex file.
6685a1cb98faSBarry Smith 
6686a1cb98faSBarry Smith   Collective
66878ca92349SMatthew G. Knepley 
66888ca92349SMatthew G. Knepley + comm        - The MPI communicator
66898ca92349SMatthew G. Knepley . filename    - Name of the .dat file
66908ca92349SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
66918ca92349SMatthew G. Knepley 
66928ca92349SMatthew G. Knepley   Output Parameter:
6693a1cb98faSBarry Smith . dm  - The `DM` object representing the mesh
66948ca92349SMatthew G. Knepley 
66958ca92349SMatthew G. Knepley   Level: beginner
66968ca92349SMatthew G. Knepley 
6697a1cb98faSBarry Smith   Note:
6698a1cb98faSBarry Smith   The format is the simplest possible:
6699a1cb98faSBarry Smith .vb
6700d0812dedSMatthew G. Knepley   dim Ne Nv Nc Nl
6701d0812dedSMatthew G. Knepley   v_1 v_2 ... v_Nc
6702d0812dedSMatthew G. Knepley   ...
6703d0812dedSMatthew G. Knepley   x y z marker_1 ... marker_Nl
6704a1cb98faSBarry Smith .ve
6705a1cb98faSBarry Smith 
6706a1cb98faSBarry Smith   Developer Note:
6707a1cb98faSBarry Smith   Should use a `PetscViewer` not a filename
6708a1cb98faSBarry Smith 
67096afe31f6SMartin Diehl .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
6710a4e35b19SJacob Faibussowitsch */
6711ff6a9541SJacob Faibussowitsch static PetscErrorCode DMPlexCreateCellVertexFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
6712d71ae5a4SJacob Faibussowitsch {
67138ca92349SMatthew G. Knepley   DMLabel      marker;
67148ca92349SMatthew G. Knepley   PetscViewer  viewer;
67158ca92349SMatthew G. Knepley   Vec          coordinates;
67168ca92349SMatthew G. Knepley   PetscSection coordSection;
67178ca92349SMatthew G. Knepley   PetscScalar *coords;
67188ca92349SMatthew G. Knepley   char         line[PETSC_MAX_PATH_LEN];
6719d0812dedSMatthew G. Knepley   PetscInt     cdim, coordSize, v, c, d;
67208ca92349SMatthew G. Knepley   PetscMPIInt  rank;
6721d0812dedSMatthew G. Knepley   int          snum, dim, Nv, Nc, Ncn, Nl;
67228ca92349SMatthew G. Knepley 
67238ca92349SMatthew G. Knepley   PetscFunctionBegin;
67249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
67259566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, &viewer));
67269566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
67279566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
67289566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetName(viewer, filename));
6729dd400576SPatrick Sanan   if (rank == 0) {
6730d0812dedSMatthew G. Knepley     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_STRING));
6731d0812dedSMatthew G. Knepley     snum = sscanf(line, "%d %d %d %d %d", &dim, &Nc, &Nv, &Ncn, &Nl);
6732d0812dedSMatthew G. Knepley     PetscCheck(snum == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
673325ce1634SJed Brown   } else {
6734f8d5e320SMatthew G. Knepley     Nc = Nv = Ncn = Nl = 0;
67358ca92349SMatthew G. Knepley   }
6736d0812dedSMatthew G. Knepley   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
6737835f2295SStefano Zampini   cdim = dim;
67389566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
67399566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
67409566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
6741835f2295SStefano Zampini   PetscCall(DMSetDimension(*dm, dim));
67429566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(*dm, cdim));
67438ca92349SMatthew G. Knepley   /* Read topology */
6744dd400576SPatrick Sanan   if (rank == 0) {
6745f8d5e320SMatthew G. Knepley     char     format[PETSC_MAX_PATH_LEN];
6746f8d5e320SMatthew G. Knepley     PetscInt cone[8];
67478ca92349SMatthew G. Knepley     int      vbuf[8], v;
67488ca92349SMatthew G. Knepley 
67499371c9d4SSatish Balay     for (c = 0; c < Ncn; ++c) {
67509371c9d4SSatish Balay       format[c * 3 + 0] = '%';
67519371c9d4SSatish Balay       format[c * 3 + 1] = 'd';
67529371c9d4SSatish Balay       format[c * 3 + 2] = ' ';
67539371c9d4SSatish Balay     }
6754f8d5e320SMatthew G. Knepley     format[Ncn * 3 - 1] = '\0';
67559566063dSJacob Faibussowitsch     for (c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, Ncn));
67569566063dSJacob Faibussowitsch     PetscCall(DMSetUp(*dm));
67578ca92349SMatthew G. Knepley     for (c = 0; c < Nc; ++c) {
67589566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, Ncn, NULL, PETSC_STRING));
6759f8d5e320SMatthew G. Knepley       switch (Ncn) {
6760d71ae5a4SJacob Faibussowitsch       case 2:
6761d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &vbuf[0], &vbuf[1]);
6762d71ae5a4SJacob Faibussowitsch         break;
6763d71ae5a4SJacob Faibussowitsch       case 3:
6764d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2]);
6765d71ae5a4SJacob Faibussowitsch         break;
6766d71ae5a4SJacob Faibussowitsch       case 4:
6767d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3]);
6768d71ae5a4SJacob Faibussowitsch         break;
6769d71ae5a4SJacob Faibussowitsch       case 6:
6770d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5]);
6771d71ae5a4SJacob Faibussowitsch         break;
6772d71ae5a4SJacob Faibussowitsch       case 8:
6773d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &vbuf[0], &vbuf[1], &vbuf[2], &vbuf[3], &vbuf[4], &vbuf[5], &vbuf[6], &vbuf[7]);
6774d71ae5a4SJacob Faibussowitsch         break;
6775d71ae5a4SJacob Faibussowitsch       default:
6776d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell shape with %d vertices", Ncn);
6777f8d5e320SMatthew G. Knepley       }
677808401ef6SPierre Jolivet       PetscCheck(snum == Ncn, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6779f8d5e320SMatthew G. Knepley       for (v = 0; v < Ncn; ++v) cone[v] = vbuf[v] + Nc;
67808ca92349SMatthew G. Knepley       /* Hexahedra are inverted */
6781f8d5e320SMatthew G. Knepley       if (Ncn == 8) {
67828ca92349SMatthew G. Knepley         PetscInt tmp = cone[1];
67838ca92349SMatthew G. Knepley         cone[1]      = cone[3];
67848ca92349SMatthew G. Knepley         cone[3]      = tmp;
67858ca92349SMatthew G. Knepley       }
67869566063dSJacob Faibussowitsch       PetscCall(DMPlexSetCone(*dm, c, cone));
67878ca92349SMatthew G. Knepley     }
67888ca92349SMatthew G. Knepley   }
67899566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(*dm));
67909566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(*dm));
67918ca92349SMatthew G. Knepley   /* Read coordinates */
67929566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
67939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(coordSection, 1));
67949566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
67959566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
67968ca92349SMatthew G. Knepley   for (v = Nc; v < Nc + Nv; ++v) {
67979566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
67989566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
67998ca92349SMatthew G. Knepley   }
68009566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(coordSection));
68019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
68029566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
68039566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
68049566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
68059566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, cdim));
68069566063dSJacob Faibussowitsch   PetscCall(VecSetType(coordinates, VECSTANDARD));
68079566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordinates, &coords));
6808dd400576SPatrick Sanan   if (rank == 0) {
6809f8d5e320SMatthew G. Knepley     char   format[PETSC_MAX_PATH_LEN];
68108ca92349SMatthew G. Knepley     double x[3];
6811f8d5e320SMatthew G. Knepley     int    l, val[3];
68128ca92349SMatthew G. Knepley 
6813f8d5e320SMatthew G. Knepley     if (Nl) {
68149371c9d4SSatish Balay       for (l = 0; l < Nl; ++l) {
68159371c9d4SSatish Balay         format[l * 3 + 0] = '%';
68169371c9d4SSatish Balay         format[l * 3 + 1] = 'd';
68179371c9d4SSatish Balay         format[l * 3 + 2] = ' ';
68189371c9d4SSatish Balay       }
6819f8d5e320SMatthew G. Knepley       format[Nl * 3 - 1] = '\0';
68209566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(*dm, "marker"));
68219566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(*dm, "marker", &marker));
6822f8d5e320SMatthew G. Knepley     }
68238ca92349SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
68249566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 3 + Nl, NULL, PETSC_STRING));
6825f8d5e320SMatthew G. Knepley       snum = sscanf(line, "%lg %lg %lg", &x[0], &x[1], &x[2]);
682608401ef6SPierre Jolivet       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
6827f8d5e320SMatthew G. Knepley       switch (Nl) {
6828d71ae5a4SJacob Faibussowitsch       case 0:
6829d71ae5a4SJacob Faibussowitsch         snum = 0;
6830d71ae5a4SJacob Faibussowitsch         break;
6831d71ae5a4SJacob Faibussowitsch       case 1:
6832d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &val[0]);
6833d71ae5a4SJacob Faibussowitsch         break;
6834d71ae5a4SJacob Faibussowitsch       case 2:
6835d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &val[0], &val[1]);
6836d71ae5a4SJacob Faibussowitsch         break;
6837d71ae5a4SJacob Faibussowitsch       case 3:
6838d71ae5a4SJacob Faibussowitsch         snum = sscanf(line, format, &val[0], &val[1], &val[2]);
6839d71ae5a4SJacob Faibussowitsch         break;
6840d71ae5a4SJacob Faibussowitsch       default:
6841d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Request support for %d labels", Nl);
6842f8d5e320SMatthew G. Knepley       }
684308401ef6SPierre Jolivet       PetscCheck(snum == Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse cell-vertex file: %s", line);
68448ca92349SMatthew G. Knepley       for (d = 0; d < cdim; ++d) coords[v * cdim + d] = x[d];
68459566063dSJacob Faibussowitsch       for (l = 0; l < Nl; ++l) PetscCall(DMLabelSetValue(marker, v + Nc, val[l]));
68468ca92349SMatthew G. Knepley     }
68478ca92349SMatthew G. Knepley   }
68489566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordinates, &coords));
68499566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
68509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
68519566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&viewer));
68528ca92349SMatthew G. Knepley   if (interpolate) {
68538ca92349SMatthew G. Knepley     DM      idm;
68548ca92349SMatthew G. Knepley     DMLabel bdlabel;
68558ca92349SMatthew G. Knepley 
68569566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
68579566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
68588ca92349SMatthew G. Knepley     *dm = idm;
68598ca92349SMatthew G. Knepley 
6860f8d5e320SMatthew G. Knepley     if (!Nl) {
68619566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(*dm, "marker"));
68629566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(*dm, "marker", &bdlabel));
68639566063dSJacob Faibussowitsch       PetscCall(DMPlexMarkBoundaryFaces(*dm, PETSC_DETERMINE, bdlabel));
68649566063dSJacob Faibussowitsch       PetscCall(DMPlexLabelComplete(*dm, bdlabel));
68658ca92349SMatthew G. Knepley     }
6866f8d5e320SMatthew G. Knepley   }
68673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
68688ca92349SMatthew G. Knepley }
68698ca92349SMatthew G. Knepley 
6870edfba7faSMatthew G. Knepley /*
6871edfba7faSMatthew G. Knepley   DMPlexCreateSTLFromFile - Create a `DMPLEX` mesh from an STL file.
6872edfba7faSMatthew G. Knepley 
6873edfba7faSMatthew G. Knepley   Collective
6874edfba7faSMatthew G. Knepley 
6875edfba7faSMatthew G. Knepley + comm        - The MPI communicator
6876edfba7faSMatthew G. Knepley . filename    - Name of the .dat file
6877edfba7faSMatthew G. Knepley - interpolate - Create faces and edges in the mesh
6878edfba7faSMatthew G. Knepley 
6879edfba7faSMatthew G. Knepley   Output Parameter:
6880edfba7faSMatthew G. Knepley . dm  - The `DM` object representing the mesh
6881edfba7faSMatthew G. Knepley 
6882edfba7faSMatthew G. Knepley   Level: beginner
6883edfba7faSMatthew G. Knepley 
6884edfba7faSMatthew G. Knepley   Notes:
6885edfba7faSMatthew G. Knepley   The binary format is:
6886edfba7faSMatthew G. Knepley .vb
6887edfba7faSMatthew G. Knepley   UINT8[80]    - Header               - 80 bytes
6888edfba7faSMatthew G. Knepley   UINT32       - Number of triangles  - 04 bytes
6889edfba7faSMatthew G. Knepley   foreach triangle                    - 50 bytes
6890edfba7faSMatthew G. Knepley     REAL32[3] - Normal vector         - 12 bytes
6891edfba7faSMatthew G. Knepley     REAL32[3] - Vertex 1              - 12 bytes
6892edfba7faSMatthew G. Knepley     REAL32[3] - Vertex 2              - 12 bytes
6893edfba7faSMatthew G. Knepley     REAL32[3] - Vertex 3              - 12 bytes
6894edfba7faSMatthew G. Knepley     UINT16    - Attribute byte count  - 02 bytes
6895edfba7faSMatthew G. Knepley   end
6896edfba7faSMatthew G. Knepley .ve
6897edfba7faSMatthew G. Knepley 
6898edfba7faSMatthew G. Knepley   The format is here <https://en.wikipedia.org/wiki/STL_(file_format)>
6899edfba7faSMatthew G. Knepley 
6900edfba7faSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
6901edfba7faSMatthew G. Knepley */
6902edfba7faSMatthew G. Knepley static PetscErrorCode DMPlexCreateSTLFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
6903edfba7faSMatthew G. Knepley {
6904edfba7faSMatthew G. Knepley   PetscViewer  viewer;
6905edfba7faSMatthew G. Knepley   Vec          coordinates;
6906edfba7faSMatthew G. Knepley   PetscSection coordSection;
6907edfba7faSMatthew G. Knepley   PetscScalar *coords;
6908edfba7faSMatthew G. Knepley   PetscInt     coordSize;
6909edfba7faSMatthew G. Knepley   char         line[PETSC_MAX_PATH_LEN];
6910edfba7faSMatthew G. Knepley   PetscBT      bt;
6911edfba7faSMatthew G. Knepley   float       *trialCoords = NULL;
6912edfba7faSMatthew G. Knepley   PetscInt    *cells       = NULL;
6913edfba7faSMatthew G. Knepley   PetscBool    isascii;
6914edfba7faSMatthew G. Knepley   PetscMPIInt  rank;
6915edfba7faSMatthew G. Knepley   PetscInt     Nc, Nv, nv = 0;
6916edfba7faSMatthew G. Knepley 
6917edfba7faSMatthew G. Knepley   PetscFunctionBegin;
6918edfba7faSMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6919edfba7faSMatthew G. Knepley   PetscCall(PetscViewerCreate(comm, &viewer));
6920edfba7faSMatthew G. Knepley   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERBINARY));
6921edfba7faSMatthew G. Knepley   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
6922edfba7faSMatthew G. Knepley   PetscCall(PetscViewerFileSetName(viewer, filename));
6923edfba7faSMatthew G. Knepley   if (rank == 0) {
6924edfba7faSMatthew G. Knepley     int num;
6925edfba7faSMatthew G. Knepley 
6926edfba7faSMatthew G. Knepley     PetscCall(PetscViewerRead(viewer, line, 5, NULL, PETSC_CHAR));
6927edfba7faSMatthew G. Knepley     line[5] = 0;
6928edfba7faSMatthew G. Knepley     PetscCall(PetscStrncmp(line, "solid", 5, &isascii));
6929edfba7faSMatthew G. Knepley     PetscCheck(!isascii, comm, PETSC_ERR_SUP, "No support for ASCII yet");
6930edfba7faSMatthew G. Knepley     PetscCall(PetscViewerRead(viewer, line, 75, NULL, PETSC_CHAR));
6931edfba7faSMatthew G. Knepley     line[75] = 0;
6932edfba7faSMatthew G. Knepley     PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_INT32));
6933edfba7faSMatthew G. Knepley     PetscCall(PetscByteSwap(&num, PETSC_INT32, 1));
6934edfba7faSMatthew G. Knepley     Nc = num;
6935edfba7faSMatthew G. Knepley     // Read facet coordinates
6936edfba7faSMatthew G. Knepley     PetscCall(PetscMalloc1(Nc * 9, &trialCoords));
6937edfba7faSMatthew G. Knepley     for (PetscInt c = 0; c < Nc; ++c) {
6938edfba7faSMatthew G. Knepley       double    normal[3];
6939edfba7faSMatthew G. Knepley       short int dummy;
6940edfba7faSMatthew G. Knepley 
6941edfba7faSMatthew G. Knepley       PetscCall(PetscViewerRead(viewer, normal, 3, NULL, PETSC_FLOAT));
6942edfba7faSMatthew G. Knepley       PetscCall(PetscViewerRead(viewer, &trialCoords[c * 9 + 0], 9, NULL, PETSC_FLOAT));
6943edfba7faSMatthew G. Knepley       PetscCall(PetscByteSwap(&trialCoords[c * 9 + 0], PETSC_FLOAT, 9));
6944edfba7faSMatthew G. Knepley       PetscCall(PetscViewerRead(viewer, &dummy, 1, NULL, PETSC_SHORT));
6945edfba7faSMatthew G. Knepley     }
6946edfba7faSMatthew G. Knepley     PetscCall(PetscMalloc1(Nc * 3, &cells));
6947edfba7faSMatthew G. Knepley     // Find unique vertices
6948edfba7faSMatthew G. Knepley     PetscCall(PetscBTCreate(Nc * 3, &bt));
6949edfba7faSMatthew G. Knepley     PetscCall(PetscBTMemzero(Nc * 3, bt));
6950edfba7faSMatthew G. Knepley     PetscCall(PetscBTSet(bt, 0));
6951edfba7faSMatthew G. Knepley     PetscCall(PetscBTSet(bt, 1));
6952edfba7faSMatthew G. Knepley     PetscCall(PetscBTSet(bt, 2));
6953edfba7faSMatthew G. Knepley     Nv       = 0;
6954edfba7faSMatthew G. Knepley     cells[0] = Nc + Nv++;
6955edfba7faSMatthew G. Knepley     cells[1] = Nc + Nv++;
6956edfba7faSMatthew G. Knepley     cells[2] = Nc + Nv++;
6957edfba7faSMatthew G. Knepley     for (PetscInt v = 3; v < Nc * 3; ++v) {
6958edfba7faSMatthew G. Knepley       PetscBool match = PETSC_FALSE;
6959edfba7faSMatthew G. Knepley 
6960edfba7faSMatthew G. Knepley       for (PetscInt w = 0, x = 0; w < v; ++w) {
6961edfba7faSMatthew G. Knepley         if (PetscBTLookup(bt, w)) {
6962edfba7faSMatthew G. Knepley           if (trialCoords[v * 3 + 0] == trialCoords[w * 3 + 0] && trialCoords[v * 3 + 1] == trialCoords[w * 3 + 1] && trialCoords[v * 3 + 2] == trialCoords[w * 3 + 2]) {
6963edfba7faSMatthew G. Knepley             match    = PETSC_TRUE;
6964edfba7faSMatthew G. Knepley             cells[v] = Nc + x;
6965edfba7faSMatthew G. Knepley             break;
6966edfba7faSMatthew G. Knepley           }
6967edfba7faSMatthew G. Knepley           ++x;
6968edfba7faSMatthew G. Knepley         }
6969edfba7faSMatthew G. Knepley       }
6970edfba7faSMatthew G. Knepley       if (!match) {
6971edfba7faSMatthew G. Knepley         PetscCall(PetscBTSet(bt, v));
6972edfba7faSMatthew G. Knepley         cells[v] = Nc + Nv++;
6973edfba7faSMatthew G. Knepley       }
6974edfba7faSMatthew G. Knepley     }
6975edfba7faSMatthew G. Knepley   } else {
6976edfba7faSMatthew G. Knepley     Nc = Nv = 0;
6977edfba7faSMatthew G. Knepley   }
6978edfba7faSMatthew G. Knepley   for (PetscInt v = 3; v < Nc * 3; ++v) PetscCheck(cells[v] < Nc + Nv, comm, PETSC_ERR_PLIB, "Invalid cells[%" PetscInt_FMT "]: %" PetscInt_FMT, v, cells[v]);
6979edfba7faSMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
6980edfba7faSMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
6981edfba7faSMatthew G. Knepley   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
6982edfba7faSMatthew G. Knepley   PetscCall(DMSetDimension(*dm, 2));
6983edfba7faSMatthew G. Knepley   PetscCall(DMSetCoordinateDim(*dm, 3));
6984edfba7faSMatthew G. Knepley   for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, 3));
6985edfba7faSMatthew G. Knepley   PetscCall(DMSetUp(*dm));
6986edfba7faSMatthew G. Knepley   for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetCone(*dm, c, &cells[c * 3]));
6987edfba7faSMatthew G. Knepley   PetscCall(PetscFree(cells));
6988edfba7faSMatthew G. Knepley   PetscCall(DMPlexSymmetrize(*dm));
6989edfba7faSMatthew G. Knepley   PetscCall(DMPlexStratify(*dm));
6990edfba7faSMatthew G. Knepley 
6991edfba7faSMatthew G. Knepley   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
6992edfba7faSMatthew G. Knepley   PetscCall(PetscSectionSetNumFields(coordSection, 1));
6993edfba7faSMatthew G. Knepley   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, 3));
6994edfba7faSMatthew G. Knepley   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
6995edfba7faSMatthew G. Knepley   for (PetscInt v = Nc; v < Nc + Nv; ++v) {
6996edfba7faSMatthew G. Knepley     PetscCall(PetscSectionSetDof(coordSection, v, 3));
6997edfba7faSMatthew G. Knepley     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, 3));
6998edfba7faSMatthew G. Knepley   }
6999edfba7faSMatthew G. Knepley   PetscCall(PetscSectionSetUp(coordSection));
7000edfba7faSMatthew G. Knepley   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
7001edfba7faSMatthew G. Knepley   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
7002edfba7faSMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
7003edfba7faSMatthew G. Knepley   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
7004edfba7faSMatthew G. Knepley   PetscCall(VecSetBlockSize(coordinates, 3));
7005edfba7faSMatthew G. Knepley   PetscCall(VecSetType(coordinates, VECSTANDARD));
7006edfba7faSMatthew G. Knepley   PetscCall(VecGetArray(coordinates, &coords));
7007edfba7faSMatthew G. Knepley   for (PetscInt tv = 0; tv < Nc * 3; ++tv) {
7008edfba7faSMatthew G. Knepley     if (PetscBTLookup(bt, tv)) {
7009edfba7faSMatthew G. Knepley       for (PetscInt d = 0; d < 3; ++d) coords[nv * 3 + d] = trialCoords[tv * 3 + d];
7010edfba7faSMatthew G. Knepley       ++nv;
7011edfba7faSMatthew G. Knepley     }
7012edfba7faSMatthew G. Knepley   }
70138c5add6aSPierre Jolivet   PetscCheck(nv == Nv, comm, PETSC_ERR_PLIB, "Number of vertices copied %" PetscInt_FMT " != %" PetscInt_FMT " number of mesh vertices", nv, Nv);
7014edfba7faSMatthew G. Knepley   PetscCall(PetscFree(trialCoords));
7015edfba7faSMatthew G. Knepley   PetscCall(PetscBTDestroy(&bt));
7016edfba7faSMatthew G. Knepley   PetscCall(VecRestoreArray(coordinates, &coords));
7017edfba7faSMatthew G. Knepley   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
7018edfba7faSMatthew G. Knepley   PetscCall(VecDestroy(&coordinates));
7019edfba7faSMatthew G. Knepley   PetscCall(PetscViewerDestroy(&viewer));
7020edfba7faSMatthew G. Knepley   if (interpolate) {
7021edfba7faSMatthew G. Knepley     DM idm;
7022edfba7faSMatthew G. Knepley 
7023edfba7faSMatthew G. Knepley     PetscCall(DMPlexInterpolate(*dm, &idm));
7024edfba7faSMatthew G. Knepley     PetscCall(DMDestroy(dm));
7025edfba7faSMatthew G. Knepley     *dm = idm;
7026edfba7faSMatthew G. Knepley   }
7027edfba7faSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7028edfba7faSMatthew G. Knepley }
7029edfba7faSMatthew G. Knepley 
7030f536a3c1SMatthew G. Knepley /*
7031f536a3c1SMatthew G. Knepley   DMPlexCreateShapefile - Create a `DMPLEX` mesh from the ESRI Shapefile format.
7032f536a3c1SMatthew G. Knepley 
7033f536a3c1SMatthew G. Knepley   Collective
7034f536a3c1SMatthew G. Knepley 
7035f536a3c1SMatthew G. Knepley + comm   - The MPI communicator
7036f536a3c1SMatthew G. Knepley - viewer - `PetscViewer` for the .shp file
7037f536a3c1SMatthew G. Knepley 
7038f536a3c1SMatthew G. Knepley   Output Parameter:
7039f536a3c1SMatthew G. Knepley . dm - The `DM` object representing the mesh
7040f536a3c1SMatthew G. Knepley 
7041f536a3c1SMatthew G. Knepley   Level: beginner
7042f536a3c1SMatthew G. Knepley 
7043f536a3c1SMatthew G. Knepley   Note:
7044f536a3c1SMatthew G. Knepley   The format is specified at [Wikipedia](https://en.wikipedia.org/wiki/Shapefile) and [ESRI](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf).
7045f536a3c1SMatthew G. Knepley 
7046f536a3c1SMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
7047f536a3c1SMatthew G. Knepley */
7048f536a3c1SMatthew G. Knepley static PetscErrorCode DMPlexCreateShapefile(MPI_Comm comm, PetscViewer viewer, DM *dm)
7049f536a3c1SMatthew G. Knepley {
7050f536a3c1SMatthew G. Knepley   Vec          coordinates;
7051f536a3c1SMatthew G. Knepley   PetscSection coordSection;
7052f536a3c1SMatthew G. Knepley   PetscScalar *coords;
7053f536a3c1SMatthew G. Knepley   PetscInt     cdim   = 2, coordSize;
7054f536a3c1SMatthew G. Knepley   int          dim    = 1, Nv, Nc, vOff;
7055f536a3c1SMatthew G. Knepley   double      *points = NULL;
7056f536a3c1SMatthew G. Knepley   double       mbr[4], zb[2], mb[2];
7057f536a3c1SMatthew G. Knepley   PetscMPIInt  rank;
7058f536a3c1SMatthew G. Knepley 
7059f536a3c1SMatthew G. Knepley   PetscFunctionBegin;
7060f536a3c1SMatthew G. Knepley   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7061f536a3c1SMatthew G. Knepley   if (rank == 0) {
7062f536a3c1SMatthew G. Knepley     PetscInt cnt;
7063f536a3c1SMatthew G. Knepley     int      magic, dummy[5], len, version, shtype, totlen = 0;
7064f536a3c1SMatthew G. Knepley 
7065f536a3c1SMatthew G. Knepley     // Read header
7066f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, &magic, 1, &cnt, PETSC_INT32));
7067f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 0-3");
7068f536a3c1SMatthew G. Knepley     PetscCheck(magic == 0x0000270a, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: invalid magic number %X", magic);
7069f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, dummy, 5, &cnt, PETSC_INT32));
7070f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 4-23");
7071f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, &len, 1, &cnt, PETSC_INT32));
7072f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 24-27");
7073f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, &version, 1, &cnt, PETSC_INT32));
7074f536a3c1SMatthew G. Knepley     PetscCall(PetscByteSwap(&version, PETSC_INT32, 1));
7075f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 28-31");
7076f536a3c1SMatthew G. Knepley     PetscCall(PetscInfo(viewer, "Shapefile: version %d file length %d\n", version, len));
7077f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, &shtype, 1, &cnt, PETSC_INT32));
7078f536a3c1SMatthew G. Knepley     PetscCall(PetscByteSwap(&shtype, PETSC_INT32, 1));
7079f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 32-35");
7080f536a3c1SMatthew G. Knepley     PetscCall(PetscInfo(viewer, "Shapefile: shape type %d\n", shtype));
7081f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, mbr, 4, &cnt, PETSC_DOUBLE));
7082f536a3c1SMatthew G. Knepley     PetscCall(PetscByteSwap(mbr, PETSC_DOUBLE, 4));
7083f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 36-67");
7084f536a3c1SMatthew G. Knepley     PetscCall(PetscInfo(viewer, "Shapefile: minimum bounding rectangle (%g, %g) -- (%g, %g)\n", mbr[0], mbr[1], mbr[2], mbr[3]));
7085f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, zb, 2, &cnt, PETSC_DOUBLE));
7086f536a3c1SMatthew G. Knepley     PetscCall(PetscByteSwap(zb, PETSC_DOUBLE, 2));
7087f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 68-83");
7088f536a3c1SMatthew G. Knepley     PetscCall(PetscInfo(viewer, "Shapefile: Z bounds (%g) -- (%g)\n", zb[0], zb[1]));
7089f536a3c1SMatthew G. Knepley     PetscCall(PetscViewerBinaryRead(viewer, mb, 2, &cnt, PETSC_DOUBLE));
7090f536a3c1SMatthew G. Knepley     PetscCall(PetscByteSwap(mb, PETSC_DOUBLE, 2));
7091f536a3c1SMatthew G. Knepley     PetscCheck(cnt == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read bytes 84-99");
7092f536a3c1SMatthew G. Knepley     PetscCall(PetscInfo(viewer, "Shapefile: M bounds (%g) -- (%g)\n", mb[0], mb[1]));
7093f536a3c1SMatthew G. Knepley     totlen += 100;
7094f536a3c1SMatthew G. Knepley     {
7095f536a3c1SMatthew G. Knepley       int    rnum, rlen, rshtype, rnpart, rnp;
7096f536a3c1SMatthew G. Knepley       double rmbr[4];
7097f536a3c1SMatthew G. Knepley       int   *partOffsets;
7098f536a3c1SMatthew G. Knepley 
7099f536a3c1SMatthew G. Knepley       // Read record header
7100f536a3c1SMatthew G. Knepley       PetscCall(PetscViewerBinaryRead(viewer, &rnum, 1, &cnt, PETSC_INT32));
7101f536a3c1SMatthew G. Knepley       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record header bytes 0-3");
7102f536a3c1SMatthew G. Knepley       PetscCall(PetscViewerBinaryRead(viewer, &rlen, 1, &cnt, PETSC_INT32));
7103f536a3c1SMatthew G. Knepley       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record header bytes 4-7");
7104f536a3c1SMatthew G. Knepley       PetscCall(PetscInfo(viewer, "Shapefile: record %d length %d\n", rnum, rlen));
7105f536a3c1SMatthew G. Knepley       totlen += 8;
7106f536a3c1SMatthew G. Knepley       // Read record
7107f536a3c1SMatthew G. Knepley       PetscCall(PetscViewerBinaryRead(viewer, &rshtype, 1, &cnt, PETSC_INT32));
7108f536a3c1SMatthew G. Knepley       PetscCall(PetscByteSwap(&rshtype, PETSC_INT32, 1));
7109f536a3c1SMatthew G. Knepley       PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 0-3");
7110f536a3c1SMatthew G. Knepley       PetscCall(PetscInfo(viewer, "Shapefile: record shape type %d\n", rshtype));
7111f536a3c1SMatthew G. Knepley       totlen += 4;
7112f536a3c1SMatthew G. Knepley       switch (rshtype) {
7113f536a3c1SMatthew G. Knepley       case 5: // Polygon
7114f536a3c1SMatthew G. Knepley         PetscCall(PetscViewerBinaryRead(viewer, rmbr, 4, &cnt, PETSC_DOUBLE));
7115f536a3c1SMatthew G. Knepley         PetscCall(PetscByteSwap(rmbr, PETSC_DOUBLE, 4));
7116f536a3c1SMatthew G. Knepley         PetscCheck(cnt == 4, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 4-35");
7117f536a3c1SMatthew G. Knepley         PetscCall(PetscInfo(viewer, "Shapefile: record minimum bounding rectangle (%g, %g) -- (%g, %g)\n", rmbr[0], rmbr[1], rmbr[2], rmbr[3]));
7118f536a3c1SMatthew G. Knepley         PetscCall(PetscViewerBinaryRead(viewer, &rnpart, 1, &cnt, PETSC_INT32));
7119f536a3c1SMatthew G. Knepley         PetscCall(PetscByteSwap(&rnpart, PETSC_INT32, 1));
7120f536a3c1SMatthew G. Knepley         PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 36-39");
7121f536a3c1SMatthew G. Knepley         PetscCall(PetscInfo(viewer, "Shapefile: record shape number of parts %d\n", rnpart));
7122f536a3c1SMatthew G. Knepley         PetscCall(PetscViewerBinaryRead(viewer, &rnp, 1, &cnt, PETSC_INT32));
7123f536a3c1SMatthew G. Knepley         PetscCall(PetscByteSwap(&rnp, PETSC_INT32, 1));
7124f536a3c1SMatthew G. Knepley         PetscCheck(cnt == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record bytes 36-39");
7125f536a3c1SMatthew G. Knepley         PetscCall(PetscInfo(viewer, "Shapefile: record shape number of points %d\n", rnp));
7126f536a3c1SMatthew G. Knepley         totlen += 40;
7127f536a3c1SMatthew G. Knepley         PetscCall(PetscMalloc1(rnpart, &partOffsets));
7128f536a3c1SMatthew G. Knepley         PetscCall(PetscViewerBinaryRead(viewer, partOffsets, rnpart, &cnt, PETSC_INT32));
7129f536a3c1SMatthew G. Knepley         PetscCall(PetscByteSwap(partOffsets, PETSC_INT32, rnpart));
7130f536a3c1SMatthew G. Knepley         PetscCheck(cnt == rnpart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record part offsets");
7131f536a3c1SMatthew G. Knepley         totlen += 4 * rnpart;
7132f536a3c1SMatthew G. Knepley         PetscCall(PetscMalloc1(rnp * 2, &points));
7133f536a3c1SMatthew G. Knepley         PetscCall(PetscViewerBinaryRead(viewer, points, rnp * 2, &cnt, PETSC_DOUBLE));
7134f536a3c1SMatthew G. Knepley         PetscCall(PetscByteSwap(points, PETSC_DOUBLE, rnp * 2));
7135f536a3c1SMatthew G. Knepley         PetscCheck(cnt == rnp * 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Shapefile file: could not read record points");
7136f536a3c1SMatthew G. Knepley         totlen += 8 * rnp * 2;
7137f536a3c1SMatthew G. Knepley         PetscCheck(totlen == 2 * len, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unable to parse Shapefile file: only support a single object: %d != %d", totlen, 2 * len);
7138f536a3c1SMatthew G. Knepley         // Only get the last polygon now
7139f536a3c1SMatthew G. Knepley         vOff = partOffsets[rnpart - 1];
7140f536a3c1SMatthew G. Knepley         Nv   = rnp - vOff;
7141f536a3c1SMatthew G. Knepley         Nc   = Nv - 1;
7142f536a3c1SMatthew G. Knepley         PetscCall(PetscInfo(viewer, "Shapefile: record first polygon size %d totlen %d\n", Nv, totlen));
7143f536a3c1SMatthew G. Knepley         PetscCall(PetscFree(partOffsets));
7144f536a3c1SMatthew G. Knepley         break;
7145f536a3c1SMatthew G. Knepley       default:
7146f536a3c1SMatthew G. Knepley         PetscCheck(0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support polygons right now");
7147f536a3c1SMatthew G. Knepley       }
7148f536a3c1SMatthew G. Knepley     }
7149f536a3c1SMatthew G. Knepley   } else {
7150f536a3c1SMatthew G. Knepley     Nc = Nv = vOff = 0;
7151f536a3c1SMatthew G. Knepley   }
7152f536a3c1SMatthew G. Knepley   PetscCallMPI(MPI_Bcast(&dim, 1, MPI_INT, 0, comm));
7153f536a3c1SMatthew G. Knepley   PetscCall(DMCreate(comm, dm));
7154f536a3c1SMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
7155f536a3c1SMatthew G. Knepley   PetscCall(DMPlexSetChart(*dm, 0, Nc + Nv));
7156f536a3c1SMatthew G. Knepley   PetscCall(DMSetDimension(*dm, dim));
7157f536a3c1SMatthew G. Knepley   PetscCall(DMSetCoordinateDim(*dm, cdim));
7158f536a3c1SMatthew G. Knepley   // Topology of a circle
7159f536a3c1SMatthew G. Knepley   if (rank == 0) {
7160f536a3c1SMatthew G. Knepley     for (PetscInt c = 0; c < Nc; ++c) PetscCall(DMPlexSetConeSize(*dm, c, 2));
7161f536a3c1SMatthew G. Knepley     PetscCall(DMSetUp(*dm));
7162f536a3c1SMatthew G. Knepley     for (PetscInt c = 0; c < Nc; ++c) {
7163f536a3c1SMatthew G. Knepley       PetscInt cone[2] = {Nc + c, Nc + c + 1};
7164f536a3c1SMatthew G. Knepley 
7165f536a3c1SMatthew G. Knepley       PetscCall(DMPlexSetCone(*dm, c, cone));
7166f536a3c1SMatthew G. Knepley     }
7167f536a3c1SMatthew G. Knepley   }
7168f536a3c1SMatthew G. Knepley   PetscCall(DMPlexSymmetrize(*dm));
7169f536a3c1SMatthew G. Knepley   PetscCall(DMPlexStratify(*dm));
7170f536a3c1SMatthew G. Knepley   // Set coordinates
7171f536a3c1SMatthew G. Knepley   PetscCall(DMGetCoordinateSection(*dm, &coordSection));
7172f536a3c1SMatthew G. Knepley   PetscCall(PetscSectionSetNumFields(coordSection, 1));
7173f536a3c1SMatthew G. Knepley   PetscCall(PetscSectionSetFieldComponents(coordSection, 0, cdim));
7174f536a3c1SMatthew G. Knepley   PetscCall(PetscSectionSetChart(coordSection, Nc, Nc + Nv));
7175f536a3c1SMatthew G. Knepley   for (PetscInt v = Nc; v < Nc + Nv; ++v) {
7176f536a3c1SMatthew G. Knepley     PetscCall(PetscSectionSetDof(coordSection, v, cdim));
7177f536a3c1SMatthew G. Knepley     PetscCall(PetscSectionSetFieldDof(coordSection, v, 0, cdim));
7178f536a3c1SMatthew G. Knepley   }
7179f536a3c1SMatthew G. Knepley   PetscCall(PetscSectionSetUp(coordSection));
7180f536a3c1SMatthew G. Knepley   PetscCall(PetscSectionGetStorageSize(coordSection, &coordSize));
7181f536a3c1SMatthew G. Knepley   PetscCall(VecCreate(PETSC_COMM_SELF, &coordinates));
7182f536a3c1SMatthew G. Knepley   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
7183f536a3c1SMatthew G. Knepley   PetscCall(VecSetSizes(coordinates, coordSize, PETSC_DETERMINE));
7184f536a3c1SMatthew G. Knepley   PetscCall(VecSetBlockSize(coordinates, cdim));
7185f536a3c1SMatthew G. Knepley   PetscCall(VecSetType(coordinates, VECSTANDARD));
7186f536a3c1SMatthew G. Knepley   PetscCall(VecGetArray(coordinates, &coords));
7187f536a3c1SMatthew G. Knepley   for (PetscInt v = 0; v < Nv; ++v) {
7188f536a3c1SMatthew G. Knepley     coords[v * cdim + 0] = points[(v + vOff) * cdim + 0] - mbr[0];
7189f536a3c1SMatthew G. Knepley     coords[v * cdim + 1] = points[(v + vOff) * cdim + 1] - mbr[1];
7190f536a3c1SMatthew G. Knepley   }
7191f536a3c1SMatthew G. Knepley   PetscCall(PetscFree(points));
7192f536a3c1SMatthew G. Knepley   PetscCall(VecRestoreArray(coordinates, &coords));
7193f536a3c1SMatthew G. Knepley   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
7194f536a3c1SMatthew G. Knepley   PetscCall(VecDestroy(&coordinates));
7195f536a3c1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7196f536a3c1SMatthew G. Knepley }
7197f536a3c1SMatthew G. Knepley 
7198f536a3c1SMatthew G. Knepley /*
7199f536a3c1SMatthew G. Knepley   DMPlexCreateShapefileFromFile - Create a `DMPLEX` mesh from the ESRI Shapefile format.
7200f536a3c1SMatthew G. Knepley 
7201f536a3c1SMatthew G. Knepley   Collective
7202f536a3c1SMatthew G. Knepley 
7203f536a3c1SMatthew G. Knepley + comm     - The MPI communicator
7204f536a3c1SMatthew G. Knepley . filename - Name of the .shp file
7205f536a3c1SMatthew G. Knepley 
7206f536a3c1SMatthew G. Knepley   Output Parameter:
7207f536a3c1SMatthew G. Knepley . dm - The `DM` object representing the mesh
7208f536a3c1SMatthew G. Knepley 
7209f536a3c1SMatthew G. Knepley   Level: beginner
7210f536a3c1SMatthew G. Knepley 
7211f536a3c1SMatthew G. Knepley   Note:
7212f536a3c1SMatthew G. Knepley   The format is specified at [Wikipedia](https://en.wikipedia.org/wiki/Shapefile) and [ESRI](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf).
7213f536a3c1SMatthew G. Knepley 
7214f536a3c1SMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
7215f536a3c1SMatthew G. Knepley */
7216f536a3c1SMatthew G. Knepley static PetscErrorCode DMPlexCreateShapefileFromFile(MPI_Comm comm, const char filename[], DM *dm)
7217f536a3c1SMatthew G. Knepley {
7218f536a3c1SMatthew G. Knepley   PetscViewer viewer;
7219f536a3c1SMatthew G. Knepley 
7220f536a3c1SMatthew G. Knepley   PetscFunctionBegin;
7221f536a3c1SMatthew G. Knepley   PetscCall(PetscViewerCreate(comm, &viewer));
7222f536a3c1SMatthew G. Knepley   PetscCall(PetscViewerSetType(viewer, PETSCVIEWERBINARY));
7223f536a3c1SMatthew G. Knepley   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
7224f536a3c1SMatthew G. Knepley   PetscCall(PetscViewerFileSetName(viewer, filename));
7225f536a3c1SMatthew G. Knepley   PetscCall(DMPlexCreateShapefile(comm, viewer, dm));
7226f536a3c1SMatthew G. Knepley   PetscCall(PetscViewerDestroy(&viewer));
7227f536a3c1SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7228f536a3c1SMatthew G. Knepley }
7229f536a3c1SMatthew G. Knepley 
7230cc4c1da9SBarry Smith /*@
7231a1cb98faSBarry Smith   DMPlexCreateFromFile - This takes a filename and produces a `DM`
7232a1cb98faSBarry Smith 
7233a1cb98faSBarry Smith   Collective
7234ca522641SMatthew G. Knepley 
7235ca522641SMatthew G. Knepley   Input Parameters:
7236ca522641SMatthew G. Knepley + comm        - The communicator
7237ca522641SMatthew G. Knepley . filename    - A file name
7238a1cb98faSBarry Smith . plexname    - The object name of the resulting `DM`, also used for intra-datafile lookup by some formats
7239ca522641SMatthew G. Knepley - interpolate - Flag to create intermediate mesh pieces (edges, faces)
7240ca522641SMatthew G. Knepley 
7241ca522641SMatthew G. Knepley   Output Parameter:
7242a1cb98faSBarry Smith . dm - The `DM`
7243ca522641SMatthew G. Knepley 
7244a1cb98faSBarry Smith   Options Database Key:
7245a1cb98faSBarry Smith . -dm_plex_create_from_hdf5_xdmf - use the `PETSC_VIEWER_HDF5_XDMF` format for reading HDF5
724602ef0d99SVaclav Hapla 
7247b44f4de4SBarry Smith   Use `-dm_plex_create_ prefix` to pass options to the internal `PetscViewer`, e.g. `-dm_plex_create_viewer_hdf5_collective`
7248bca97951SVaclav Hapla 
7249ca522641SMatthew G. Knepley   Level: beginner
7250ca522641SMatthew G. Knepley 
7251a1cb98faSBarry Smith   Notes:
7252a1cb98faSBarry Smith   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
7253a1cb98faSBarry Smith   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
7254a1cb98faSBarry Smith   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
7255a1cb98faSBarry Smith   The input parameter name is thus used to name the `DMPLEX` object when `DMPlexCreateFromFile()` internally
7256a1cb98faSBarry Smith   calls `DMLoad()`. Currently, name is ignored for other viewer types and/or formats.
7257a1cb98faSBarry Smith 
72581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`, `PetscObjectSetName()`, `DMView()`, `DMLoad()`
7259ca522641SMatthew G. Knepley @*/
7260d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateFromFile(MPI_Comm comm, const char filename[], const char plexname[], PetscBool interpolate, DM *dm)
7261d71ae5a4SJacob Faibussowitsch {
7262ef3a5affSJacob Faibussowitsch   const char  extGmsh[]      = ".msh";
7263ef3a5affSJacob Faibussowitsch   const char  extGmsh2[]     = ".msh2";
7264ef3a5affSJacob Faibussowitsch   const char  extGmsh4[]     = ".msh4";
7265ef3a5affSJacob Faibussowitsch   const char  extCGNS[]      = ".cgns";
7266ef3a5affSJacob Faibussowitsch   const char  extExodus[]    = ".exo";
7267ef3a5affSJacob Faibussowitsch   const char  extExodus_e[]  = ".e";
7268ef3a5affSJacob Faibussowitsch   const char  extGenesis[]   = ".gen";
7269ef3a5affSJacob Faibussowitsch   const char  extFluent[]    = ".cas";
7270ef3a5affSJacob Faibussowitsch   const char  extHDF5[]      = ".h5";
72716f2c871aSStefano Zampini   const char  extXDMFHDF5[]  = ".xdmf.h5";
7272ef3a5affSJacob Faibussowitsch   const char  extPLY[]       = ".ply";
72735552b385SBrandon   const char  extEGADSlite[] = ".egadslite";
7274ef3a5affSJacob Faibussowitsch   const char  extEGADS[]     = ".egads";
7275ef3a5affSJacob Faibussowitsch   const char  extIGES[]      = ".igs";
72765552b385SBrandon   const char  extIGES2[]     = ".iges";
7277ef3a5affSJacob Faibussowitsch   const char  extSTEP[]      = ".stp";
72785552b385SBrandon   const char  extSTEP2[]     = ".step";
72795552b385SBrandon   const char  extBREP[]      = ".brep";
7280ef3a5affSJacob Faibussowitsch   const char  extCV[]        = ".dat";
7281edfba7faSMatthew G. Knepley   const char  extSTL[]       = ".stl";
7282f536a3c1SMatthew G. Knepley   const char  extSHP[]       = ".shp";
7283ca522641SMatthew G. Knepley   size_t      len;
7284f536a3c1SMatthew G. Knepley   PetscBool   isGmsh, isGmsh2, isGmsh4, isCGNS, isExodus, isGenesis, isFluent, isHDF5, isPLY, isEGADSlite, isEGADS, isIGES, isIGES2, isSTEP, isSTEP2, isBREP, isCV, isSTL, isSHP, isXDMFHDF5;
7285ca522641SMatthew G. Knepley   PetscMPIInt rank;
7286ca522641SMatthew G. Knepley 
7287ca522641SMatthew G. Knepley   PetscFunctionBegin;
72884f572ea9SToby Isaac   PetscAssertPointer(filename, 2);
72894f572ea9SToby Isaac   if (plexname) PetscAssertPointer(plexname, 3);
72904f572ea9SToby Isaac   PetscAssertPointer(dm, 5);
72919566063dSJacob Faibussowitsch   PetscCall(DMInitializePackage());
72929566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CreateFromFile, 0, 0, 0, 0));
72939566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
72949566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(filename, &len));
729528b400f6SJacob Faibussowitsch   PetscCheck(len, comm, PETSC_ERR_ARG_WRONG, "Filename must be a valid path");
7296ef3a5affSJacob Faibussowitsch 
72979371c9d4SSatish Balay #define CheckExtension(extension__, is_extension__) \
72989371c9d4SSatish Balay   do { \
7299274aaeaaSJacob Faibussowitsch     PetscAssert(sizeof(extension__), comm, PETSC_ERR_PLIB, "Zero-size extension: %s", extension__); \
7300274aaeaaSJacob Faibussowitsch     /* don't count the null-terminator at the end */ \
7301274aaeaaSJacob Faibussowitsch     const size_t ext_len = sizeof(extension__) - 1; \
7302274aaeaaSJacob Faibussowitsch     if (len < ext_len) { \
7303ef3a5affSJacob Faibussowitsch       is_extension__ = PETSC_FALSE; \
7304ef3a5affSJacob Faibussowitsch     } else { \
7305274aaeaaSJacob Faibussowitsch       PetscCall(PetscStrncmp(filename + len - ext_len, extension__, ext_len, &is_extension__)); \
7306ef3a5affSJacob Faibussowitsch     } \
7307ef3a5affSJacob Faibussowitsch   } while (0)
7308ef3a5affSJacob Faibussowitsch 
7309ef3a5affSJacob Faibussowitsch   CheckExtension(extGmsh, isGmsh);
7310ef3a5affSJacob Faibussowitsch   CheckExtension(extGmsh2, isGmsh2);
7311ef3a5affSJacob Faibussowitsch   CheckExtension(extGmsh4, isGmsh4);
7312ef3a5affSJacob Faibussowitsch   CheckExtension(extCGNS, isCGNS);
7313ef3a5affSJacob Faibussowitsch   CheckExtension(extExodus, isExodus);
7314ef3a5affSJacob Faibussowitsch   if (!isExodus) CheckExtension(extExodus_e, isExodus);
7315ef3a5affSJacob Faibussowitsch   CheckExtension(extGenesis, isGenesis);
7316ef3a5affSJacob Faibussowitsch   CheckExtension(extFluent, isFluent);
7317ef3a5affSJacob Faibussowitsch   CheckExtension(extHDF5, isHDF5);
7318ef3a5affSJacob Faibussowitsch   CheckExtension(extPLY, isPLY);
73195552b385SBrandon   CheckExtension(extEGADSlite, isEGADSlite);
7320ef3a5affSJacob Faibussowitsch   CheckExtension(extEGADS, isEGADS);
7321ef3a5affSJacob Faibussowitsch   CheckExtension(extIGES, isIGES);
73225552b385SBrandon   CheckExtension(extIGES2, isIGES2);
7323ef3a5affSJacob Faibussowitsch   CheckExtension(extSTEP, isSTEP);
73245552b385SBrandon   CheckExtension(extSTEP2, isSTEP2);
73255552b385SBrandon   CheckExtension(extBREP, isBREP);
7326ef3a5affSJacob Faibussowitsch   CheckExtension(extCV, isCV);
7327edfba7faSMatthew G. Knepley   CheckExtension(extSTL, isSTL);
7328f536a3c1SMatthew G. Knepley   CheckExtension(extSHP, isSHP);
73296f2c871aSStefano Zampini   CheckExtension(extXDMFHDF5, isXDMFHDF5);
7330ef3a5affSJacob Faibussowitsch 
7331ef3a5affSJacob Faibussowitsch #undef CheckExtension
7332ef3a5affSJacob Faibussowitsch 
7333de78e4feSLisandro Dalcin   if (isGmsh || isGmsh2 || isGmsh4) {
73349566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateGmshFromFile(comm, filename, interpolate, dm));
7335ca522641SMatthew G. Knepley   } else if (isCGNS) {
73369566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateCGNSFromFile(comm, filename, interpolate, dm));
733790c68965SMatthew G. Knepley   } else if (isExodus || isGenesis) {
73389566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateExodusFromFile(comm, filename, interpolate, dm));
73392f0bd6dcSMichael Lange   } else if (isFluent) {
73409566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFluentFromFile(comm, filename, interpolate, dm));
7341cc2f8f65SMatthew G. Knepley   } else if (isHDF5) {
7342cc2f8f65SMatthew G. Knepley     PetscViewer viewer;
7343cc2f8f65SMatthew G. Knepley 
734443b242b4SVaclav Hapla     /* PETSC_VIEWER_HDF5_XDMF is used if the filename ends with .xdmf.h5, or if -dm_plex_create_from_hdf5_xdmf option is present */
73456f2c871aSStefano Zampini     PetscCall(PetscOptionsGetBool(NULL, NULL, "-dm_plex_create_from_hdf5_xdmf", &isXDMFHDF5, NULL));
73469566063dSJacob Faibussowitsch     PetscCall(PetscViewerCreate(comm, &viewer));
73479566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetType(viewer, PETSCVIEWERHDF5));
73489566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetOptionsPrefix(viewer, "dm_plex_create_"));
73499566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetFromOptions(viewer));
73509566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
73519566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetName(viewer, filename));
7352cd7e8a5eSksagiyam 
73539566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, dm));
7354f4f49eeaSPierre Jolivet     PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
73559566063dSJacob Faibussowitsch     PetscCall(DMSetType(*dm, DMPLEX));
73566f2c871aSStefano Zampini     if (isXDMFHDF5) PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_XDMF));
73579566063dSJacob Faibussowitsch     PetscCall(DMLoad(*dm, viewer));
73586f2c871aSStefano Zampini     if (isXDMFHDF5) PetscCall(PetscViewerPopFormat(viewer));
73599566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
73605fd9971aSMatthew G. Knepley 
73615fd9971aSMatthew G. Knepley     if (interpolate) {
73625fd9971aSMatthew G. Knepley       DM idm;
73635fd9971aSMatthew G. Knepley 
73649566063dSJacob Faibussowitsch       PetscCall(DMPlexInterpolate(*dm, &idm));
73659566063dSJacob Faibussowitsch       PetscCall(DMDestroy(dm));
73665fd9971aSMatthew G. Knepley       *dm = idm;
73675fd9971aSMatthew G. Knepley     }
7368f2801cd6SMatthew G. Knepley   } else if (isPLY) {
73699566063dSJacob Faibussowitsch     PetscCall(DMPlexCreatePLYFromFile(comm, filename, interpolate, dm));
73705552b385SBrandon   } else if (isEGADSlite || isEGADS || isIGES || isIGES2 || isSTEP || isSTEP2 || isBREP) {
73715552b385SBrandon     PetscCall(DMPlexCreateGeomFromFile(comm, filename, dm, isEGADSlite));
73725552b385SBrandon 
73737bee2925SMatthew Knepley     if (!interpolate) {
73747bee2925SMatthew Knepley       DM udm;
73757bee2925SMatthew Knepley 
73769566063dSJacob Faibussowitsch       PetscCall(DMPlexUninterpolate(*dm, &udm));
73779566063dSJacob Faibussowitsch       PetscCall(DMDestroy(dm));
73787bee2925SMatthew Knepley       *dm = udm;
73797bee2925SMatthew Knepley     }
73808ca92349SMatthew G. Knepley   } else if (isCV) {
73819566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateCellVertexFromFile(comm, filename, interpolate, dm));
7382edfba7faSMatthew G. Knepley   } else if (isSTL) {
7383edfba7faSMatthew G. Knepley     PetscCall(DMPlexCreateSTLFromFile(comm, filename, interpolate, dm));
7384f536a3c1SMatthew G. Knepley   } else if (isSHP) {
7385f536a3c1SMatthew G. Knepley     PetscCall(DMPlexCreateShapefileFromFile(comm, filename, dm));
738698921bdaSJacob Faibussowitsch   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot load file %s: unrecognized extension", filename);
73879566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(plexname, &len));
7388f4f49eeaSPierre Jolivet   if (len) PetscCall(PetscObjectSetName((PetscObject)*dm, plexname));
73899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreateFromFile, 0, 0, 0, 0));
73903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7391ca522641SMatthew G. Knepley }
739212b8a6daSStefano Zampini 
7393cc4c1da9SBarry Smith /*@
73949f6c5813SMatthew G. Knepley   DMPlexCreateEphemeral - This takes a `DMPlexTransform` and a base `DMPlex` and produces an ephemeral `DM`, meaning one that is created on the fly in response to queries.
73959f6c5813SMatthew G. Knepley 
73960528010dSStefano Zampini   Input Parameters:
73970528010dSStefano Zampini + tr     - The `DMPlexTransform`
73980528010dSStefano Zampini - prefix - An options prefix, or NULL
73999f6c5813SMatthew G. Knepley 
74009f6c5813SMatthew G. Knepley   Output Parameter:
74019f6c5813SMatthew G. Knepley . dm - The `DM`
74029f6c5813SMatthew G. Knepley 
74039f6c5813SMatthew G. Knepley   Level: beginner
74049f6c5813SMatthew G. Knepley 
740520f4b53cSBarry Smith   Notes:
740620f4b53cSBarry Smith   An emphemeral mesh is one that is not stored concretely, as in the default `DMPLEX` implementation, but rather is produced on the fly in response to queries, using information from the transform and the base mesh.
740720f4b53cSBarry Smith 
74089f6c5813SMatthew G. Knepley .seealso: `DMPlexCreateFromFile`, `DMPlexCreateFromDAG()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCreate()`
74099f6c5813SMatthew G. Knepley @*/
74100528010dSStefano Zampini PetscErrorCode DMPlexCreateEphemeral(DMPlexTransform tr, const char prefix[], DM *dm)
74119f6c5813SMatthew G. Knepley {
74120528010dSStefano Zampini   DM           bdm, bcdm, cdm;
74130528010dSStefano Zampini   Vec          coordinates, coordinatesNew;
74140528010dSStefano Zampini   PetscSection cs;
7415817b2c36SMatthew G. Knepley   PetscInt     cdim, Nl;
74169f6c5813SMatthew G. Knepley 
74179f6c5813SMatthew G. Knepley   PetscFunctionBegin;
74189f6c5813SMatthew G. Knepley   PetscCall(DMCreate(PetscObjectComm((PetscObject)tr), dm));
74199f6c5813SMatthew G. Knepley   PetscCall(DMSetType(*dm, DMPLEX));
74200528010dSStefano Zampini   ((DM_Plex *)(*dm)->data)->interpolated = DMPLEX_INTERPOLATED_FULL;
74210528010dSStefano Zampini   // Handle coordinates
74220528010dSStefano Zampini   PetscCall(DMPlexTransformGetDM(tr, &bdm));
7423817b2c36SMatthew G. Knepley   PetscCall(DMPlexTransformSetDimensions(tr, bdm, *dm));
7424817b2c36SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(*dm, &cdim));
74250528010dSStefano Zampini   PetscCall(DMGetCoordinateDM(bdm, &bcdm));
74260528010dSStefano Zampini   PetscCall(DMGetCoordinateDM(*dm, &cdm));
74270528010dSStefano Zampini   PetscCall(DMCopyDisc(bcdm, cdm));
74280528010dSStefano Zampini   PetscCall(DMGetLocalSection(cdm, &cs));
74290528010dSStefano Zampini   PetscCall(PetscSectionSetNumFields(cs, 1));
74300528010dSStefano Zampini   PetscCall(PetscSectionSetFieldComponents(cs, 0, cdim));
74310528010dSStefano Zampini   PetscCall(DMGetCoordinatesLocal(bdm, &coordinates));
74320528010dSStefano Zampini   PetscCall(VecDuplicate(coordinates, &coordinatesNew));
74330528010dSStefano Zampini   PetscCall(VecCopy(coordinates, coordinatesNew));
74340528010dSStefano Zampini   PetscCall(DMSetCoordinatesLocal(*dm, coordinatesNew));
74350528010dSStefano Zampini   PetscCall(VecDestroy(&coordinatesNew));
74369f6c5813SMatthew G. Knepley 
74379f6c5813SMatthew G. Knepley   PetscCall(PetscObjectReference((PetscObject)tr));
74389f6c5813SMatthew G. Knepley   PetscCall(DMPlexTransformDestroy(&((DM_Plex *)(*dm)->data)->tr));
74399f6c5813SMatthew G. Knepley   ((DM_Plex *)(*dm)->data)->tr = tr;
74400528010dSStefano Zampini   PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE));
74410528010dSStefano Zampini   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*dm, prefix));
74420528010dSStefano Zampini   PetscCall(DMSetFromOptions(*dm));
74439f6c5813SMatthew G. Knepley 
74449f6c5813SMatthew G. Knepley   PetscCall(DMGetNumLabels(bdm, &Nl));
74459f6c5813SMatthew G. Knepley   for (PetscInt l = 0; l < Nl; ++l) {
74469f6c5813SMatthew G. Knepley     DMLabel     label, labelNew;
74479f6c5813SMatthew G. Knepley     const char *lname;
74489f6c5813SMatthew G. Knepley     PetscBool   isDepth, isCellType;
74499f6c5813SMatthew G. Knepley 
74509f6c5813SMatthew G. Knepley     PetscCall(DMGetLabelName(bdm, l, &lname));
74519f6c5813SMatthew G. Knepley     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
74529f6c5813SMatthew G. Knepley     if (isDepth) continue;
74539f6c5813SMatthew G. Knepley     PetscCall(PetscStrcmp(lname, "celltype", &isCellType));
74549f6c5813SMatthew G. Knepley     if (isCellType) continue;
74559f6c5813SMatthew G. Knepley     PetscCall(DMCreateLabel(*dm, lname));
74569f6c5813SMatthew G. Knepley     PetscCall(DMGetLabel(bdm, lname, &label));
74579f6c5813SMatthew G. Knepley     PetscCall(DMGetLabel(*dm, lname, &labelNew));
74589f6c5813SMatthew G. Knepley     PetscCall(DMLabelSetType(labelNew, DMLABELEPHEMERAL));
74599f6c5813SMatthew G. Knepley     PetscCall(DMLabelEphemeralSetLabel(labelNew, label));
74609f6c5813SMatthew G. Knepley     PetscCall(DMLabelEphemeralSetTransform(labelNew, tr));
74619f6c5813SMatthew G. Knepley     PetscCall(DMLabelSetUp(labelNew));
74629f6c5813SMatthew G. Knepley   }
74633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74649f6c5813SMatthew G. Knepley }
7465