Date: 2022-03-04T17:38:27+00:00

Actual source code: plexgmsh.c

      1: #define PETSCDM_DLL
      2: #include <petsc/private/dmpleximpl.h>
      3: #include <petsc/private/hashmapi.h>

      5: #include <../src/dm/impls/plex/gmshlex.h>

      7: #define GMSH_LEXORDER_ITEM(T, p)                                   \
      8: static int *GmshLexOrder_##T##_##p(void)                           \
      9: {                                                                  \
     10:   static int Gmsh_LexOrder_##T##_##p[GmshNumNodes_##T(p)] = {-1};  \
     11:   int *lex = Gmsh_LexOrder_##T##_##p;                              \
     12:   if (lex[0] == -1) (void)GmshLexOrder_##T(p, lex, 0);             \
     13:   return lex;                                                      \
     14: }

     16: #define GMSH_LEXORDER_LIST(T) \
     17: GMSH_LEXORDER_ITEM(T,  1)     \
     18: GMSH_LEXORDER_ITEM(T,  2)     \
     19: GMSH_LEXORDER_ITEM(T,  3)     \
     20: GMSH_LEXORDER_ITEM(T,  4)     \
     21: GMSH_LEXORDER_ITEM(T,  5)     \
     22: GMSH_LEXORDER_ITEM(T,  6)     \
     23: GMSH_LEXORDER_ITEM(T,  7)     \
     24: GMSH_LEXORDER_ITEM(T,  8)     \
     25: GMSH_LEXORDER_ITEM(T,  9)     \
     26: GMSH_LEXORDER_ITEM(T, 10)

     28: GMSH_LEXORDER_ITEM(VTX, 0)
     29: GMSH_LEXORDER_LIST(SEG)
     30: GMSH_LEXORDER_LIST(TRI)
     31: GMSH_LEXORDER_LIST(QUA)
     32: GMSH_LEXORDER_LIST(TET)
     33: GMSH_LEXORDER_LIST(HEX)
     34: GMSH_LEXORDER_LIST(PRI)
     35: GMSH_LEXORDER_LIST(PYR)

     37: typedef enum {
     38:   GMSH_VTX = 0,
     39:   GMSH_SEG = 1,
     40:   GMSH_TRI = 2,
     41:   GMSH_QUA = 3,
     42:   GMSH_TET = 4,
     43:   GMSH_HEX = 5,
     44:   GMSH_PRI = 6,
     45:   GMSH_PYR = 7,
     46:   GMSH_NUM_POLYTOPES = 8
     47: } GmshPolytopeType;

     49: typedef struct {
     50:   int   cellType;
     51:   int   polytope;
     52:   int   dim;
     53:   int   order;
     54:   int   numVerts;
     55:   int   numNodes;
     56:   int* (*lexorder)(void);
     57: } GmshCellInfo;

     59: #define GmshCellEntry(cellType, polytope, dim, order) \
     60:   {cellType, GMSH_##polytope, dim, order, \
     61:    GmshNumNodes_##polytope(1), \
     62:    GmshNumNodes_##polytope(order), \
     63:    GmshLexOrder_##polytope##_##order}

     65: static const GmshCellInfo GmshCellTable[] = {
     66:   GmshCellEntry( 15, VTX, 0,  0),

     68:   GmshCellEntry(  1, SEG, 1,  1),
     69:   GmshCellEntry(  8, SEG, 1,  2),
     70:   GmshCellEntry( 26, SEG, 1,  3),
     71:   GmshCellEntry( 27, SEG, 1,  4),
     72:   GmshCellEntry( 28, SEG, 1,  5),
     73:   GmshCellEntry( 62, SEG, 1,  6),
     74:   GmshCellEntry( 63, SEG, 1,  7),
     75:   GmshCellEntry( 64, SEG, 1,  8),
     76:   GmshCellEntry( 65, SEG, 1,  9),
     77:   GmshCellEntry( 66, SEG, 1, 10),

     79:   GmshCellEntry(  2, TRI, 2,  1),
     80:   GmshCellEntry(  9, TRI, 2,  2),
     81:   GmshCellEntry( 21, TRI, 2,  3),
     82:   GmshCellEntry( 23, TRI, 2,  4),
     83:   GmshCellEntry( 25, TRI, 2,  5),
     84:   GmshCellEntry( 42, TRI, 2,  6),
     85:   GmshCellEntry( 43, TRI, 2,  7),
     86:   GmshCellEntry( 44, TRI, 2,  8),
     87:   GmshCellEntry( 45, TRI, 2,  9),
     88:   GmshCellEntry( 46, TRI, 2, 10),

     90:   GmshCellEntry(  3, QUA, 2,  1),
     91:   GmshCellEntry( 10, QUA, 2,  2),
     92:   GmshCellEntry( 36, QUA, 2,  3),
     93:   GmshCellEntry( 37, QUA, 2,  4),
     94:   GmshCellEntry( 38, QUA, 2,  5),
     95:   GmshCellEntry( 47, QUA, 2,  6),
     96:   GmshCellEntry( 48, QUA, 2,  7),
     97:   GmshCellEntry( 49, QUA, 2,  8),
     98:   GmshCellEntry( 50, QUA, 2,  9),
     99:   GmshCellEntry( 51, QUA, 2, 10),

    101:   GmshCellEntry(  4, TET, 3,  1),
    102:   GmshCellEntry( 11, TET, 3,  2),
    103:   GmshCellEntry( 29, TET, 3,  3),
    104:   GmshCellEntry( 30, TET, 3,  4),
    105:   GmshCellEntry( 31, TET, 3,  5),
    106:   GmshCellEntry( 71, TET, 3,  6),
    107:   GmshCellEntry( 72, TET, 3,  7),
    108:   GmshCellEntry( 73, TET, 3,  8),
    109:   GmshCellEntry( 74, TET, 3,  9),
    110:   GmshCellEntry( 75, TET, 3, 10),

    112:   GmshCellEntry(  5, HEX, 3,  1),
    113:   GmshCellEntry( 12, HEX, 3,  2),
    114:   GmshCellEntry( 92, HEX, 3,  3),
    115:   GmshCellEntry( 93, HEX, 3,  4),
    116:   GmshCellEntry( 94, HEX, 3,  5),
    117:   GmshCellEntry( 95, HEX, 3,  6),
    118:   GmshCellEntry( 96, HEX, 3,  7),
    119:   GmshCellEntry( 97, HEX, 3,  8),
    120:   GmshCellEntry( 98, HEX, 3,  9),
    121:   GmshCellEntry( -1, HEX, 3, 10),

    123:   GmshCellEntry(  6, PRI, 3,  1),
    124:   GmshCellEntry( 13, PRI, 3,  2),
    125:   GmshCellEntry( 90, PRI, 3,  3),
    126:   GmshCellEntry( 91, PRI, 3,  4),
    127:   GmshCellEntry(106, PRI, 3,  5),
    128:   GmshCellEntry(107, PRI, 3,  6),
    129:   GmshCellEntry(108, PRI, 3,  7),
    130:   GmshCellEntry(109, PRI, 3,  8),
    131:   GmshCellEntry(110, PRI, 3,  9),
    132:   GmshCellEntry( -1, PRI, 3, 10),

    134:   GmshCellEntry(  7, PYR, 3,  1),
    135:   GmshCellEntry( 14, PYR, 3,  2),
    136:   GmshCellEntry(118, PYR, 3,  3),
    137:   GmshCellEntry(119, PYR, 3,  4),
    138:   GmshCellEntry(120, PYR, 3,  5),
    139:   GmshCellEntry(121, PYR, 3,  6),
    140:   GmshCellEntry(122, PYR, 3,  7),
    141:   GmshCellEntry(123, PYR, 3,  8),
    142:   GmshCellEntry(124, PYR, 3,  9),
    143:   GmshCellEntry( -1, PYR, 3, 10)

    145: #if 0
    146:   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
    147:   {16, GMSH_QUA, 2, 2, 4,  8, NULL},
    148:   {17, GMSH_HEX, 3, 2, 8, 20, NULL},
    149:   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
    150:   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
    151: #endif
    152: };

    154: static GmshCellInfo GmshCellMap[150];

    156: static PetscErrorCode GmshCellInfoSetUp(void)
    157: {
    158:   size_t           i, n;
    159:   static PetscBool called = PETSC_FALSE;

    161:   if (called) return 0;
    163:   called = PETSC_TRUE;
    164:   n = sizeof(GmshCellMap)/sizeof(GmshCellMap[0]);
    165:   for (i = 0; i < n; ++i) {
    166:     GmshCellMap[i].cellType = -1;
    167:     GmshCellMap[i].polytope = -1;
    168:   }
    169:   n = sizeof(GmshCellTable)/sizeof(GmshCellTable[0]);
    170:   for (i = 0; i < n; ++i) {
    171:     if (GmshCellTable[i].cellType <= 0) continue;
    172:     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
    173:   }
    174:   return(0);
    175: }

    177: #define GmshCellTypeCheck(ct) 0; do { \
    178:     const int _ct_ = (int)ct; \
    179:     if (_ct_ < 0 || _ct_ >= (int)(sizeof(GmshCellMap)/sizeof(GmshCellMap[0]))) \
    180:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); \
    181:     if (GmshCellMap[_ct_].cellType != _ct_) \
    182:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
    183:     if (GmshCellMap[_ct_].polytope == -1) \
    184:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
    185:   } while (0)

    187: typedef struct {
    188:   PetscViewer  viewer;
    189:   int          fileFormat;
    190:   int          dataSize;
    191:   PetscBool    binary;
    192:   PetscBool    byteSwap;
    193:   size_t       wlen;
    194:   void        *wbuf;
    195:   size_t       slen;
    196:   void        *sbuf;
    197:   PetscInt    *nbuf;
    198:   PetscInt     nodeStart;
    199:   PetscInt     nodeEnd;
    200:   PetscInt    *nodeMap;
    201: } GmshFile;

    203: static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
    204: {
    205:   size_t         size = count * eltsize;

    209:   if (gmsh->wlen < size) {
    210:     PetscFree(gmsh->wbuf);
    211:     PetscMalloc(size, &gmsh->wbuf);
    212:     gmsh->wlen = size;
    213:   }
    214:   *(void**)buf = size ? gmsh->wbuf : NULL;
    215:   return(0);
    216: }

    218: static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
    219: {
    220:   size_t         dataSize = (size_t)gmsh->dataSize;
    221:   size_t         size = count * dataSize;

    225:   if (gmsh->slen < size) {
    226:     PetscFree(gmsh->sbuf);
    227:     PetscMalloc(size, &gmsh->sbuf);
    228:     gmsh->slen = size;
    229:   }
    230:   *(void**)buf = size ? gmsh->sbuf : NULL;
    231:   return(0);
    232: }

    234: static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
    235: {
    238:   PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype);
    239:   if (gmsh->byteSwap) {PetscByteSwap(buf, dtype, count);}
    240:   return(0);
    241: }

    243: static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
    244: {
    247:   PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING);
    248:   return(0);
    249: }

    251: static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
    252: {
    255:   PetscStrcmp(line, Section, match);
    256:   return(0);
    257: }

    259: static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
    260: {
    261:   PetscBool      match;

    265:   GmshMatch(gmsh, Section, line, &match);
    266:   if (!match) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s",Section);
    267:   return(0);
    268: }

    270: static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
    271: {
    272:   PetscBool      match;

    276:   while (PETSC_TRUE) {
    277:     GmshReadString(gmsh, line, 1);
    278:     GmshMatch(gmsh, "$Comments", line, &match);
    279:     if (!match) break;
    280:     while (PETSC_TRUE) {
    281:       GmshReadString(gmsh, line, 1);
    282:       GmshMatch(gmsh, "$EndComments", line, &match);
    283:       if (match) break;
    284:     }
    285:   }
    286:   return(0);
    287: }

    289: static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
    290: {
    293:   GmshReadString(gmsh, line, 1);
    294:   GmshExpect(gmsh, EndSection, line);
    295:   return(0);
    296: }

    298: static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
    299: {
    300:   PetscInt       i;
    301:   size_t         dataSize = (size_t)gmsh->dataSize;

    305:   if (dataSize == sizeof(PetscInt)) {
    306:     GmshRead(gmsh, buf, count, PETSC_INT);
    307:   } else  if (dataSize == sizeof(int)) {
    308:     int *ibuf = NULL;
    309:     GmshBufferSizeGet(gmsh, count, &ibuf);
    310:     GmshRead(gmsh, ibuf, count, PETSC_ENUM);
    311:     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
    312:   } else  if (dataSize == sizeof(long)) {
    313:     long *ibuf = NULL;
    314:     GmshBufferSizeGet(gmsh, count, &ibuf);
    315:     GmshRead(gmsh, ibuf, count, PETSC_LONG);
    316:     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
    317:   } else if (dataSize == sizeof(PetscInt64)) {
    318:     PetscInt64 *ibuf = NULL;
    319:     GmshBufferSizeGet(gmsh, count, &ibuf);
    320:     GmshRead(gmsh, ibuf, count, PETSC_INT64);
    321:     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
    322:   }
    323:   return(0);
    324: }

    326: static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
    327: {
    330:   GmshRead(gmsh, buf, count, PETSC_ENUM);
    331:   return(0);
    332: }

    334: static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
    335: {
    338:   GmshRead(gmsh, buf, count, PETSC_DOUBLE);
    339:   return(0);
    340: }

    342: typedef struct {
    343:   PetscInt id;       /* Entity ID */
    344:   PetscInt dim;      /* Dimension */
    345:   double   bbox[6];  /* Bounding box */
    346:   PetscInt numTags;  /* Size of tag array */
    347:   int      tags[4];  /* Tag array */
    348: } GmshEntity;

    350: typedef struct {
    351:   GmshEntity *entity[4];
    352:   PetscHMapI  entityMap[4];
    353: } GmshEntities;

    355: static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
    356: {
    357:   PetscInt       dim;

    361:   PetscNew(entities);
    362:   for (dim = 0; dim < 4; ++dim) {
    363:     PetscCalloc1(count[dim], &(*entities)->entity[dim]);
    364:     PetscHMapICreate(&(*entities)->entityMap[dim]);
    365:   }
    366:   return(0);
    367: }

    369: static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
    370: {
    371:   PetscInt       dim;

    375:   if (!*entities) return(0);
    376:   for (dim = 0; dim < 4; ++dim) {
    377:     PetscFree((*entities)->entity[dim]);
    378:     PetscHMapIDestroy(&(*entities)->entityMap[dim]);
    379:   }
    380:   PetscFree((*entities));
    381:   return(0);
    382: }

    384: static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity** entity)
    385: {

    389:   PetscHMapISet(entities->entityMap[dim], eid, index);
    390:   entities->entity[dim][index].dim = dim;
    391:   entities->entity[dim][index].id  = eid;
    392:   if (entity) *entity = &entities->entity[dim][index];
    393:   return(0);
    394: }

    396: static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity** entity)
    397: {
    398:   PetscInt       index;

    402:   PetscHMapIGet(entities->entityMap[dim], eid, &index);
    403:   *entity = &entities->entity[dim][index];
    404:   return(0);
    405: }

    407: typedef struct {
    408:   PetscInt *id;   /* Node IDs */
    409:   double   *xyz;  /* Coordinates */
    410: } GmshNodes;

    412: static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
    413: {

    417:   PetscNew(nodes);
    418:   PetscMalloc1(count*1, &(*nodes)->id);
    419:   PetscMalloc1(count*3, &(*nodes)->xyz);
    420:   return(0);
    421: }

    423: static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
    424: {
    427:   if (!*nodes) return(0);
    428:   PetscFree((*nodes)->id);
    429:   PetscFree((*nodes)->xyz);
    430:   PetscFree((*nodes));
    431:   return(0);
    432: }

    434: typedef struct {
    435:   PetscInt id;       /* Element ID */
    436:   PetscInt dim;      /* Dimension */
    437:   PetscInt cellType; /* Cell type */
    438:   PetscInt numVerts; /* Size of vertex array */
    439:   PetscInt numNodes; /* Size of node array */
    440:   PetscInt *nodes;   /* Vertex/Node array */
    441:   PetscInt numTags;  /* Size of tag array */
    442:   int      tags[4];  /* Tag array */
    443: } GmshElement;

    445: static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
    446: {

    450:   PetscCalloc1(count, elements);
    451:   return(0);
    452: }

    454: static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
    455: {

    459:   if (!*elements) return(0);
    460:   PetscFree(*elements);
    461:   return(0);
    462: }

    464: typedef struct {
    465:   PetscInt       dim;
    466:   PetscInt       order;
    467:   GmshEntities  *entities;
    468:   PetscInt       numNodes;
    469:   GmshNodes     *nodelist;
    470:   PetscInt       numElems;
    471:   GmshElement   *elements;
    472:   PetscInt       numVerts;
    473:   PetscInt       numCells;
    474:   PetscInt      *periodMap;
    475:   PetscInt      *vertexMap;
    476:   PetscSegBuffer segbuf;
    477: } GmshMesh;

    479: static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
    480: {

    484:   PetscNew(mesh);
    485:   PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf);
    486:   return(0);
    487: }

    489: static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
    490: {

    494:   if (!*mesh) return(0);
    495:   GmshEntitiesDestroy(&(*mesh)->entities);
    496:   GmshNodesDestroy(&(*mesh)->nodelist);
    497:   GmshElementsDestroy(&(*mesh)->elements);
    498:   PetscFree((*mesh)->periodMap);
    499:   PetscFree((*mesh)->vertexMap);
    500:   PetscSegBufferDestroy(&(*mesh)->segbuf);
    501:   PetscFree((*mesh));
    502:   return(0);
    503: }

    505: static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
    506: {
    507:   PetscViewer    viewer = gmsh->viewer;
    508:   PetscBool      byteSwap = gmsh->byteSwap;
    509:   char           line[PETSC_MAX_PATH_LEN];
    510:   int            n, num, nid, snum;
    511:   GmshNodes      *nodes;

    515:   PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);
    516:   snum = sscanf(line, "%d", &num);
    517:   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    518:   GmshNodesCreate(num, &nodes);
    519:   mesh->numNodes = num;
    520:   mesh->nodelist = nodes;
    521:   for (n = 0; n < num; ++n) {
    522:     double *xyz = nodes->xyz + n*3;
    523:     PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);
    524:     PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);
    525:     if (byteSwap) {PetscByteSwap(&nid, PETSC_ENUM, 1);}
    526:     if (byteSwap) {PetscByteSwap(xyz, PETSC_DOUBLE, 3);}
    527:     nodes->id[n] = nid;
    528:   }
    529:   return(0);
    530: }

    532: /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
    533:    file contents multiple times to figure out the true number of cells and facets
    534:    in the given mesh. To make this more efficient we read the file contents only
    535:    once and store them in memory, while determining the true number of cells. */
    536: static PetscErrorCode GmshReadElements_v22(GmshFile* gmsh, GmshMesh *mesh)
    537: {
    538:   PetscViewer    viewer = gmsh->viewer;
    539:   PetscBool      binary = gmsh->binary;
    540:   PetscBool      byteSwap = gmsh->byteSwap;
    541:   char           line[PETSC_MAX_PATH_LEN];
    542:   int            i, c, p, num, ibuf[1+4+1000], snum;
    543:   int            cellType, numElem, numVerts, numNodes, numTags;
    544:   GmshElement   *elements;
    545:   PetscInt      *nodeMap = gmsh->nodeMap;

    549:   PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);
    550:   snum = sscanf(line, "%d", &num);
    551:   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    552:   GmshElementsCreate(num, &elements);
    553:   mesh->numElems = num;
    554:   mesh->elements = elements;
    555:   for (c = 0; c < num;) {
    556:     PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);
    557:     if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, 3);}

    559:     cellType = binary ? ibuf[0] : ibuf[1];
    560:     numElem  = binary ? ibuf[1] : 1;
    561:     numTags  = ibuf[2];

    563:     GmshCellTypeCheck(cellType);
    564:     numVerts = GmshCellMap[cellType].numVerts;
    565:     numNodes = GmshCellMap[cellType].numNodes;

    567:     for (i = 0; i < numElem; ++i, ++c) {
    568:       GmshElement *element = elements + c;
    569:       const int off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
    570:       const int *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
    571:       PetscViewerRead(viewer, ibuf+off, nint, NULL, PETSC_ENUM);
    572:       if (byteSwap) {PetscByteSwap(ibuf+off, PETSC_ENUM, nint);}
    573:       element->id  = id[0];
    574:       element->dim = GmshCellMap[cellType].dim;
    575:       element->cellType = cellType;
    576:       element->numVerts = numVerts;
    577:       element->numNodes = numNodes;
    578:       element->numTags  = PetscMin(numTags, 4);
    579:       PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);
    580:       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
    581:       for (p = 0; p < element->numTags;  p++) element->tags[p]  = tags[p];
    582:     }
    583:   }
    584:   return(0);
    585: }

    587: /*
    588: $Entities
    589:   numPoints(unsigned long) numCurves(unsigned long)
    590:     numSurfaces(unsigned long) numVolumes(unsigned long)
    591:   // points
    592:   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
    593:     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
    594:     numPhysicals(unsigned long) phyisicalTag[...](int)
    595:   ...
    596:   // curves
    597:   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
    598:      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
    599:      numPhysicals(unsigned long) physicalTag[...](int)
    600:      numBREPVert(unsigned long) tagBREPVert[...](int)
    601:   ...
    602:   // surfaces
    603:   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
    604:     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
    605:     numPhysicals(unsigned long) physicalTag[...](int)
    606:     numBREPCurve(unsigned long) tagBREPCurve[...](int)
    607:   ...
    608:   // volumes
    609:   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
    610:     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
    611:     numPhysicals(unsigned long) physicalTag[...](int)
    612:     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
    613:   ...
    614: $EndEntities
    615: */
    616: static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
    617: {
    618:   PetscViewer    viewer = gmsh->viewer;
    619:   PetscBool      byteSwap = gmsh->byteSwap;
    620:   long           index, num, lbuf[4];
    621:   int            dim, eid, numTags, *ibuf, t;
    622:   PetscInt       count[4], i;
    623:   GmshEntity     *entity = NULL;

    627:   PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG);
    628:   if (byteSwap) {PetscByteSwap(lbuf, PETSC_LONG, 4);}
    629:   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
    630:   GmshEntitiesCreate(count, &mesh->entities);
    631:   for (dim = 0; dim < 4; ++dim) {
    632:     for (index = 0; index < count[dim]; ++index) {
    633:       PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM);
    634:       if (byteSwap) {PetscByteSwap(&eid, PETSC_ENUM, 1);}
    635:       GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);
    636:       PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE);
    637:       if (byteSwap) {PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6);}
    638:       PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);
    639:       if (byteSwap) {PetscByteSwap(&num, PETSC_LONG, 1);}
    640:       GmshBufferGet(gmsh, num, sizeof(int), &ibuf);
    641:       PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);
    642:       if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, num);}
    643:       entity->numTags = numTags = (int) PetscMin(num, 4);
    644:       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
    645:       if (dim == 0) continue;
    646:       PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);
    647:       if (byteSwap) {PetscByteSwap(&num, PETSC_LONG, 1);}
    648:       GmshBufferGet(gmsh, num, sizeof(int), &ibuf);
    649:       PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);
    650:       if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, num);}
    651:     }
    652:   }
    653:   return(0);
    654: }

    656: /*
    657: $Nodes
    658:   numEntityBlocks(unsigned long) numNodes(unsigned long)
    659:   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
    660:     tag(int) x(double) y(double) z(double)
    661:     ...
    662:   ...
    663: $EndNodes
    664: */
    665: static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
    666: {
    667:   PetscViewer    viewer = gmsh->viewer;
    668:   PetscBool      byteSwap = gmsh->byteSwap;
    669:   long           block, node, n, numEntityBlocks, numTotalNodes, numNodes;
    670:   int            info[3], nid;
    671:   GmshNodes      *nodes;

    675:   PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);
    676:   if (byteSwap) {PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);}
    677:   PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG);
    678:   if (byteSwap) {PetscByteSwap(&numTotalNodes, PETSC_LONG, 1);}
    679:   GmshNodesCreate(numTotalNodes, &nodes);
    680:   mesh->numNodes = numTotalNodes;
    681:   mesh->nodelist = nodes;
    682:   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
    683:     PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);
    684:     PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG);
    685:     if (byteSwap) {PetscByteSwap(&numNodes, PETSC_LONG, 1);}
    686:     if (gmsh->binary) {
    687:       size_t nbytes = sizeof(int) + 3*sizeof(double);
    688:       char   *cbuf = NULL; /* dummy value to prevent warning from compiler about possible unitilized value */
    689:       GmshBufferGet(gmsh, numNodes, nbytes, &cbuf);
    690:       PetscViewerRead(viewer, cbuf, numNodes*nbytes, NULL, PETSC_CHAR);
    691:       for (node = 0; node < numNodes; ++node, ++n) {
    692:         char   *cnid = cbuf + node*nbytes, *cxyz = cnid + sizeof(int);
    693:         double *xyz = nodes->xyz + n*3;
    694:         if (!PetscBinaryBigEndian()) {PetscByteSwap(cnid, PETSC_ENUM, 1);}
    695:         if (!PetscBinaryBigEndian()) {PetscByteSwap(cxyz, PETSC_DOUBLE, 3);}
    696:         PetscMemcpy(&nid, cnid, sizeof(int));
    697:         PetscMemcpy(xyz, cxyz, 3*sizeof(double));
    698:         if (byteSwap) {PetscByteSwap(&nid, PETSC_ENUM, 1);}
    699:         if (byteSwap) {PetscByteSwap(xyz, PETSC_DOUBLE, 3);}
    700:         nodes->id[n] = nid;
    701:       }
    702:     } else {
    703:       for (node = 0; node < numNodes; ++node, ++n) {
    704:         double *xyz = nodes->xyz + n*3;
    705:         PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);
    706:         PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);
    707:         if (byteSwap) {PetscByteSwap(&nid, PETSC_ENUM, 1);}
    708:         if (byteSwap) {PetscByteSwap(xyz, PETSC_DOUBLE, 3);}
    709:         nodes->id[n] = nid;
    710:       }
    711:     }
    712:   }
    713:   return(0);
    714: }

    716: /*
    717: $Elements
    718:   numEntityBlocks(unsigned long) numElements(unsigned long)
    719:   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
    720:     tag(int) numVert[...](int)
    721:     ...
    722:   ...
    723: $EndElements
    724: */
    725: static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
    726: {
    727:   PetscViewer    viewer = gmsh->viewer;
    728:   PetscBool      byteSwap = gmsh->byteSwap;
    729:   long           c, block, numEntityBlocks, numTotalElements, elem, numElements;
    730:   int            p, info[3], *ibuf = NULL;
    731:   int            eid, dim, cellType, numVerts, numNodes, numTags;
    732:   GmshEntity     *entity = NULL;
    733:   GmshElement    *elements;
    734:   PetscInt       *nodeMap = gmsh->nodeMap;

    738:   PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);
    739:   if (byteSwap) {PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);}
    740:   PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG);
    741:   if (byteSwap) {PetscByteSwap(&numTotalElements, PETSC_LONG, 1);}
    742:   GmshElementsCreate(numTotalElements, &elements);
    743:   mesh->numElems = numTotalElements;
    744:   mesh->elements = elements;
    745:   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
    746:     PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);
    747:     if (byteSwap) {PetscByteSwap(info, PETSC_ENUM, 3);}
    748:     eid = info[0]; dim = info[1]; cellType = info[2];
    749:     GmshEntitiesGet(mesh->entities, dim, eid, &entity);
    750:     GmshCellTypeCheck(cellType);
    751:     numVerts = GmshCellMap[cellType].numVerts;
    752:     numNodes = GmshCellMap[cellType].numNodes;
    753:     numTags  = entity->numTags;
    754:     PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG);
    755:     if (byteSwap) {PetscByteSwap(&numElements, PETSC_LONG, 1);}
    756:     GmshBufferGet(gmsh, (1+numNodes)*numElements, sizeof(int), &ibuf);
    757:     PetscViewerRead(viewer, ibuf, (1+numNodes)*numElements, NULL, PETSC_ENUM);
    758:     if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, (1+numNodes)*numElements);}
    759:     for (elem = 0; elem < numElements; ++elem, ++c) {
    760:       GmshElement *element = elements + c;
    761:       const int *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
    762:       element->id  = id[0];
    763:       element->dim = dim;
    764:       element->cellType = cellType;
    765:       element->numVerts = numVerts;
    766:       element->numNodes = numNodes;
    767:       element->numTags  = numTags;
    768:       PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);
    769:       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
    770:       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
    771:     }
    772:   }
    773:   return(0);
    774: }

    776: static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
    777: {
    778:   PetscViewer    viewer = gmsh->viewer;
    779:   int            fileFormat = gmsh->fileFormat;
    780:   PetscBool      binary = gmsh->binary;
    781:   PetscBool      byteSwap = gmsh->byteSwap;
    782:   int            numPeriodic, snum, i;
    783:   char           line[PETSC_MAX_PATH_LEN];
    784:   PetscInt       *nodeMap = gmsh->nodeMap;

    788:   if (fileFormat == 22 || !binary) {
    789:     PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);
    790:     snum = sscanf(line, "%d", &numPeriodic);
    791:     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    792:   } else {
    793:     PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM);
    794:     if (byteSwap) {PetscByteSwap(&numPeriodic, PETSC_ENUM, 1);}
    795:   }
    796:   for (i = 0; i < numPeriodic; i++) {
    797:     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
    798:     long   j, nNodes;
    799:     double affine[16];

    801:     if (fileFormat == 22 || !binary) {
    802:       PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);
    803:       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
    804:       if (snum != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    805:     } else {
    806:       PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);
    807:       if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, 3);}
    808:       correspondingDim = ibuf[0]; correspondingTag = ibuf[1]; primaryTag = ibuf[2];
    809:     }
    810:     (void)correspondingDim; (void)correspondingTag; (void)primaryTag; /* unused */

    812:     if (fileFormat == 22 || !binary) {
    813:       PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);
    814:       snum = sscanf(line, "%ld", &nNodes);
    815:       if (snum != 1) { /* discard transformation and try again */
    816:         PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING);
    817:         PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);
    818:         snum = sscanf(line, "%ld", &nNodes);
    819:         if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    820:       }
    821:     } else {
    822:       PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);
    823:       if (byteSwap) {PetscByteSwap(&nNodes, PETSC_LONG, 1);}
    824:       if (nNodes == -1) { /* discard transformation and try again */
    825:         PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE);
    826:         PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);
    827:         if (byteSwap) {PetscByteSwap(&nNodes, PETSC_LONG, 1);}
    828:       }
    829:     }

    831:     for (j = 0; j < nNodes; j++) {
    832:       if (fileFormat == 22 || !binary) {
    833:         PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);
    834:         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
    835:         if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    836:       } else {
    837:         PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM);
    838:         if (byteSwap) {PetscByteSwap(ibuf, PETSC_ENUM, 2);}
    839:         correspondingNode = ibuf[0]; primaryNode = ibuf[1];
    840:       }
    841:       correspondingNode  = (int) nodeMap[correspondingNode];
    842:       primaryNode = (int) nodeMap[primaryNode];
    843:       periodicMap[correspondingNode] = primaryNode;
    844:     }
    845:   }
    846:   return(0);
    847: }

    849: /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
    850: $Entities
    851:   numPoints(size_t) numCurves(size_t)
    852:     numSurfaces(size_t) numVolumes(size_t)
    853:   pointTag(int) X(double) Y(double) Z(double)
    854:     numPhysicalTags(size_t) physicalTag(int) ...
    855:   ...
    856:   curveTag(int) minX(double) minY(double) minZ(double)
    857:     maxX(double) maxY(double) maxZ(double)
    858:     numPhysicalTags(size_t) physicalTag(int) ...
    859:     numBoundingPoints(size_t) pointTag(int) ...
    860:   ...
    861:   surfaceTag(int) minX(double) minY(double) minZ(double)
    862:     maxX(double) maxY(double) maxZ(double)
    863:     numPhysicalTags(size_t) physicalTag(int) ...
    864:     numBoundingCurves(size_t) curveTag(int) ...
    865:   ...
    866:   volumeTag(int) minX(double) minY(double) minZ(double)
    867:     maxX(double) maxY(double) maxZ(double)
    868:     numPhysicalTags(size_t) physicalTag(int) ...
    869:     numBoundngSurfaces(size_t) surfaceTag(int) ...
    870:   ...
    871: $EndEntities
    872: */
    873: static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
    874: {
    875:   PetscInt       count[4], index, numTags, i;
    876:   int            dim, eid, *tags = NULL;
    877:   GmshEntity     *entity = NULL;

    881:   GmshReadSize(gmsh, count, 4);
    882:   GmshEntitiesCreate(count, &mesh->entities);
    883:   for (dim = 0; dim < 4; ++dim) {
    884:     for (index = 0; index < count[dim]; ++index) {
    885:       GmshReadInt(gmsh, &eid, 1);
    886:       GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);
    887:       GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6);
    888:       GmshReadSize(gmsh, &numTags, 1);
    889:       GmshBufferGet(gmsh, numTags, sizeof(int), &tags);
    890:       GmshReadInt(gmsh, tags, numTags);
    891:       entity->numTags = PetscMin(numTags, 4);
    892:       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
    893:       if (dim == 0) continue;
    894:       GmshReadSize(gmsh, &numTags, 1);
    895:       GmshBufferGet(gmsh, numTags, sizeof(int), &tags);
    896:       GmshReadInt(gmsh, tags, numTags);
    897:     }
    898:   }
    899:   return(0);
    900: }

    902: /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
    903: $Nodes
    904:   numEntityBlocks(size_t) numNodes(size_t)
    905:     minNodeTag(size_t) maxNodeTag(size_t)
    906:   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
    907:     nodeTag(size_t)
    908:     ...
    909:     x(double) y(double) z(double)
    910:        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
    911:        < v(double; if parametric and entityDim = 2) >
    912:     ...
    913:   ...
    914: $EndNodes
    915: */
    916: static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
    917: {
    918:   int            info[3];
    919:   PetscInt       sizes[4], numEntityBlocks, numNodes, numNodesBlock = 0, block, node;
    920:   GmshNodes      *nodes;

    924:   GmshReadSize(gmsh, sizes, 4);
    925:   numEntityBlocks = sizes[0]; numNodes = sizes[1];
    926:   GmshNodesCreate(numNodes, &nodes);
    927:   mesh->numNodes = numNodes;
    928:   mesh->nodelist = nodes;
    929:   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
    930:     GmshReadInt(gmsh, info, 3);
    931:     if (info[2] != 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
    932:     GmshReadSize(gmsh, &numNodesBlock, 1);
    933:     GmshReadSize(gmsh, nodes->id+node, numNodesBlock);
    934:     GmshReadDouble(gmsh, nodes->xyz+node*3, numNodesBlock*3);
    935:   }
    936:   gmsh->nodeStart = sizes[2];
    937:   gmsh->nodeEnd   = sizes[3]+1;
    938:   return(0);
    939: }

    941: /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
    942: $Elements
    943:   numEntityBlocks(size_t) numElements(size_t)
    944:     minElementTag(size_t) maxElementTag(size_t)
    945:   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
    946:     elementTag(size_t) nodeTag(size_t) ...
    947:     ...
    948:   ...
    949: $EndElements
    950: */
    951: static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
    952: {
    953:   int            info[3], eid, dim, cellType;
    954:   PetscInt       sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
    955:   GmshEntity     *entity = NULL;
    956:   GmshElement    *elements;
    957:   PetscInt       *nodeMap = gmsh->nodeMap;

    961:   GmshReadSize(gmsh, sizes, 4);
    962:   numEntityBlocks = sizes[0]; numElements = sizes[1];
    963:   GmshElementsCreate(numElements, &elements);
    964:   mesh->numElems = numElements;
    965:   mesh->elements = elements;
    966:   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
    967:     GmshReadInt(gmsh, info, 3);
    968:     dim = info[0]; eid = info[1]; cellType = info[2];
    969:     GmshEntitiesGet(mesh->entities, dim, eid, &entity);
    970:     GmshCellTypeCheck(cellType);
    971:     numVerts = GmshCellMap[cellType].numVerts;
    972:     numNodes = GmshCellMap[cellType].numNodes;
    973:     numTags  = entity->numTags;
    974:     GmshReadSize(gmsh, &numBlockElements, 1);
    975:     GmshBufferGet(gmsh, (1+numNodes)*numBlockElements, sizeof(PetscInt), &ibuf);
    976:     GmshReadSize(gmsh, ibuf, (1+numNodes)*numBlockElements);
    977:     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
    978:       GmshElement *element = elements + c;
    979:       const PetscInt *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
    980:       element->id  = id[0];
    981:       element->dim = dim;
    982:       element->cellType = cellType;
    983:       element->numVerts = numVerts;
    984:       element->numNodes = numNodes;
    985:       element->numTags  = numTags;
    986:       PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);
    987:       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
    988:       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
    989:     }
    990:   }
    991:   return(0);
    992: }

    994: /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
    995: $Periodic
    996:   numPeriodicLinks(size_t)
    997:   entityDim(int) entityTag(int) entityTagPrimary(int)
    998:   numAffine(size_t) value(double) ...
    999:   numCorrespondingNodes(size_t)
    1000:     nodeTag(size_t) nodeTagPrimary(size_t)
    1001:     ...
    1002:   ...
    1003: $EndPeriodic
    1004: */
    1005: static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
    1006: {
    1007:   int            info[3];
    1008:   double         dbuf[16];
    1009:   PetscInt       numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
    1010:   PetscInt       *nodeMap = gmsh->nodeMap;

    1014:   GmshReadSize(gmsh, &numPeriodicLinks, 1);
    1015:   for (link = 0; link < numPeriodicLinks; ++link) {
    1016:     GmshReadInt(gmsh, info, 3);
    1017:     GmshReadSize(gmsh, &numAffine, 1);
    1018:     GmshReadDouble(gmsh, dbuf, numAffine);
    1019:     GmshReadSize(gmsh, &numCorrespondingNodes, 1);
    1020:     GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags);
    1021:     GmshReadSize(gmsh, nodeTags, numCorrespondingNodes*2);
    1022:     for (node = 0; node < numCorrespondingNodes; ++node) {
    1023:       PetscInt correspondingNode = nodeMap[nodeTags[node*2+0]];
    1024:       PetscInt primaryNode = nodeMap[nodeTags[node*2+1]];
    1025:       periodicMap[correspondingNode] = primaryNode;
    1026:     }
    1027:   }
    1028:   return(0);
    1029: }

    1031: /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
    1032: $MeshFormat // same as MSH version 2
    1033:   version(ASCII double; currently 4.1)
    1034:   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
    1035:   data-size(ASCII int; sizeof(size_t))
    1036:   < int with value one; only in binary mode, to detect endianness >
    1037: $EndMeshFormat
    1038: */
    1039: static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
    1040: {
    1041:   char           line[PETSC_MAX_PATH_LEN];
    1042:   int            snum, fileType, fileFormat, dataSize, checkEndian;
    1043:   float          version;

    1047:   GmshReadString(gmsh, line, 3);
    1048:   snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
    1049:   if (snum != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
    1050:   if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
    1051:   if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
    1052:   if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
    1053:   if (gmsh->binary && !fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
    1054:   if (!gmsh->binary && fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
    1055:   fileFormat = (int)roundf(version*10);
    1056:   if (fileFormat <= 40 && dataSize != sizeof(double)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
    1057:   if (fileFormat >= 41 && dataSize != sizeof(int) && dataSize != sizeof(PetscInt64)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
    1058:   gmsh->fileFormat = fileFormat;
    1059:   gmsh->dataSize = dataSize;
    1060:   gmsh->byteSwap = PETSC_FALSE;
    1061:   if (gmsh->binary) {
    1062:     GmshReadInt(gmsh, &checkEndian, 1);
    1063:     if (checkEndian != 1) {
    1064:       PetscByteSwap(&checkEndian, PETSC_ENUM, 1);
    1065:       if (checkEndian != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
    1066:       gmsh->byteSwap = PETSC_TRUE;
    1067:     }
    1068:   }
    1069:   return(0);
    1070: }

    1072: /*
    1073: PhysicalNames
    1074:   numPhysicalNames(ASCII int)
    1075:   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
    1076:   ...
    1077: $EndPhysicalNames
    1078: */
    1079: static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh)
    1080: {
    1081:   char           line[PETSC_MAX_PATH_LEN], name[128+2], *p, *q;
    1082:   int            snum, numRegions, region, dim, tag;

    1086:   GmshReadString(gmsh, line, 1);
    1087:   snum = sscanf(line, "%d", &numRegions);
    1088:   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    1089:   for (region = 0; region < numRegions; ++region) {
    1090:     GmshReadString(gmsh, line, 2);
    1091:     snum = sscanf(line, "%d %d", &dim, &tag);
    1092:     if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    1093:     GmshReadString(gmsh, line, -(PetscInt)sizeof(line));
    1094:     PetscStrchr(line, '"', &p);
    1095:     if (!p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    1096:     PetscStrrchr(line, '"', &q);
    1097:     if (q == p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
    1098:     PetscStrncpy(name, p+1, (size_t)(q-p-1));
    1099:   }
    1100:   return(0);
    1101: }

    1103: static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
    1104: {

    1108:   switch (gmsh->fileFormat) {
    1109:   case 41: GmshReadEntities_v41(gmsh, mesh); break;
    1110:   default: GmshReadEntities_v40(gmsh, mesh); break;
    1111:   }
    1112:   return(0);
    1113: }

    1115: static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
    1116: {

    1120:   switch (gmsh->fileFormat) {
    1121:   case 41: GmshReadNodes_v41(gmsh, mesh); break;
    1122:   case 40: GmshReadNodes_v40(gmsh, mesh); break;
    1123:   default: GmshReadNodes_v22(gmsh, mesh); break;
    1124:   }

    1126:   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
    1127:     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
    1128:       PetscInt  tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
    1129:       GmshNodes *nodes = mesh->nodelist;
    1130:       for (n = 0; n < mesh->numNodes; ++n) {
    1131:         const PetscInt tag = nodes->id[n];
    1132:         tagMin = PetscMin(tag, tagMin);
    1133:         tagMax = PetscMax(tag, tagMax);
    1134:       }
    1135:       gmsh->nodeStart = tagMin;
    1136:       gmsh->nodeEnd   = tagMax+1;
    1137:     }
    1138:   }

    1140:   { /* Support for sparse node tags */
    1141:     PetscInt  n, t;
    1142:     GmshNodes *nodes = mesh->nodelist;
    1143:     PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf);
    1144:     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
    1145:     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
    1146:     for (n = 0; n < mesh->numNodes; ++n) {
    1147:       const PetscInt tag = nodes->id[n];
    1148:       if (gmsh->nodeMap[tag] >= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %D", tag);
    1149:       gmsh->nodeMap[tag] = n;
    1150:     }
    1151:   }
    1152:   return(0);
    1153: }

    1155: static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
    1156: {

    1160:   switch (gmsh->fileFormat) {
    1161:   case 41: GmshReadElements_v41(gmsh, mesh); break;
    1162:   case 40: GmshReadElements_v40(gmsh, mesh); break;
    1163:   default: GmshReadElements_v22(gmsh, mesh); break;
    1164:   }

    1166:   { /* Reorder elements by codimension and polytope type */
    1167:     PetscInt    ne = mesh->numElems;
    1168:     GmshElement *elements = mesh->elements;
    1169:     PetscInt    keymap[GMSH_NUM_POLYTOPES], nk = 0;
    1170:     PetscInt    offset[GMSH_NUM_POLYTOPES+1], e, k;

    1172:     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
    1173:     PetscMemzero(offset,sizeof(offset));

    1175:     keymap[GMSH_TET] = nk++;
    1176:     keymap[GMSH_HEX] = nk++;
    1177:     keymap[GMSH_PRI] = nk++;
    1178:     keymap[GMSH_PYR] = nk++;
    1179:     keymap[GMSH_TRI] = nk++;
    1180:     keymap[GMSH_QUA] = nk++;
    1181:     keymap[GMSH_SEG] = nk++;
    1182:     keymap[GMSH_VTX] = nk++;

    1184:     GmshElementsCreate(mesh->numElems, &mesh->elements);
    1185: #define key(eid) keymap[GmshCellMap[elements[(eid)].cellType].polytope]
    1186:     for (e = 0; e < ne; ++e) offset[1+key(e)]++;
    1187:     for (k = 1; k < nk; ++k) offset[k] += offset[k-1];
    1188:     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
    1189: #undef key
    1190:     GmshElementsDestroy(&elements);
    1191:   }

    1193:   { /* Mesh dimension and order */
    1194:     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
    1195:     mesh->dim   = elem ? GmshCellMap[elem->cellType].dim   : 0;
    1196:     mesh->order = elem ? GmshCellMap[elem->cellType].order : 0;
    1197:   }

    1199:   {
    1200:     PetscBT  vtx;
    1201:     PetscInt dim = mesh->dim, e, n, v;

    1203:     PetscBTCreate(mesh->numNodes, &vtx);

    1205:     /* Compute number of cells and set of vertices */
    1206:     mesh->numCells = 0;
    1207:     for (e = 0; e < mesh->numElems; ++e) {
    1208:       GmshElement *elem = mesh->elements + e;
    1209:       if (elem->dim == dim && dim > 0) mesh->numCells++;
    1210:       for (v = 0; v < elem->numVerts; v++) {
    1211:         PetscBTSet(vtx, elem->nodes[v]);
    1212:       }
    1213:     }

    1215:     /* Compute numbering for vertices */
    1216:     mesh->numVerts = 0;
    1217:     PetscMalloc1(mesh->numNodes, &mesh->vertexMap);
    1218:     for (n = 0; n < mesh->numNodes; ++n)
    1219:       mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;

    1221:     PetscBTDestroy(&vtx);
    1222:   }
    1223:   return(0);
    1224: }

    1226: static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
    1227: {
    1228:   PetscInt       n;

    1232:   PetscMalloc1(mesh->numNodes, &mesh->periodMap);
    1233:   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
    1234:   switch (gmsh->fileFormat) {
    1235:   case 41: GmshReadPeriodic_v41(gmsh, mesh->periodMap); break;
    1236:   default: GmshReadPeriodic_v40(gmsh, mesh->periodMap); break;
    1237:   }

    1239:   /* Find canonical primary nodes */
    1240:   for (n = 0; n < mesh->numNodes; ++n)
    1241:     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]])
    1242:       mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];

    1244:   /* Renumber vertices (filter out correspondings) */
    1245:   mesh->numVerts = 0;
    1246:   for (n = 0; n < mesh->numNodes; ++n)
    1247:     if (mesh->vertexMap[n] >= 0)   /* is vertex */
    1248:       if (mesh->periodMap[n] == n) /* is primary */
    1249:         mesh->vertexMap[n] = mesh->numVerts++;
    1250:   for (n = 0; n < mesh->numNodes; ++n)
    1251:     if (mesh->vertexMap[n] >= 0)   /* is vertex */
    1252:       if (mesh->periodMap[n] != n) /* is corresponding  */
    1253:         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
    1254:   return(0);
    1255: }

    1257: #define DM_POLYTOPE_VERTEX  DM_POLYTOPE_POINT
    1258: #define DM_POLYTOPE_PYRAMID DM_POLYTOPE_UNKNOWN
    1259: static const DMPolytopeType DMPolytopeMap[] = {
    1260:   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
    1261:   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
    1262:   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
    1263:   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
    1264:   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
    1265:   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
    1266:   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
    1267:   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,
    1268:   DM_POLYTOPE_UNKNOWN
    1269: };

    1271: PETSC_STATIC_INLINE DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
    1272: {
    1273:   return DMPolytopeMap[GmshCellMap[cellType].polytope];
    1274: }

    1276: static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
    1277: {
    1278:   DM              K;
    1279:   PetscSpace      P;
    1280:   PetscDualSpace  Q;
    1281:   PetscQuadrature q, fq;
    1282:   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
    1283:   PetscBool       endpoint = PETSC_TRUE;
    1284:   char            name[32];
    1285:   PetscErrorCode  ierr;

    1288:   /* Create space */
    1289:   PetscSpaceCreate(comm, &P);
    1290:   PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL);
    1291:   PetscSpacePolynomialSetTensor(P, isTensor);
    1292:   PetscSpaceSetNumComponents(P, Nc);
    1293:   PetscSpaceSetNumVariables(P, dim);
    1294:   PetscSpaceSetDegree(P, k, PETSC_DETERMINE);
    1295:   if (prefix) {
    1296:     PetscObjectSetOptionsPrefix((PetscObject) P, prefix);
    1297:     PetscSpaceSetFromOptions(P);
    1298:     PetscObjectSetOptionsPrefix((PetscObject) P, NULL);
    1299:     PetscSpaceGetDegree(P, &k, NULL);
    1300:   }
    1301:   PetscSpaceSetUp(P);
    1302:   /* Create dual space */
    1303:   PetscDualSpaceCreate(comm, &Q);
    1304:   PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE);
    1305:   PetscDualSpaceLagrangeSetTensor(Q, isTensor);
    1306:   PetscDualSpaceLagrangeSetContinuity(Q, continuity);
    1307:   PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0);
    1308:   PetscDualSpaceSetNumComponents(Q, Nc);
    1309:   PetscDualSpaceSetOrder(Q, k);
    1310:   PetscDualSpaceCreateReferenceCell(Q, dim, isSimplex, &K);
    1311:   PetscDualSpaceSetDM(Q, K);
    1312:   DMDestroy(&K);
    1313:   if (prefix) {
    1314:     PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);
    1315:     PetscDualSpaceSetFromOptions(Q);
    1316:     PetscObjectSetOptionsPrefix((PetscObject) Q, NULL);
    1317:   }
    1318:   PetscDualSpaceSetUp(Q);
    1319:   /* Create quadrature */
    1320:   if (isSimplex) {
    1321:     PetscDTStroudConicalQuadrature(dim,   1, k+1, -1, +1, &q);
    1322:     PetscDTStroudConicalQuadrature(dim-1, 1, k+1, -1, +1, &fq);
    1323:   } else {
    1324:     PetscDTGaussTensorQuadrature(dim,   1, k+1, -1, +1, &q);
    1325:     PetscDTGaussTensorQuadrature(dim-1, 1, k+1, -1, +1, &fq);
    1326:   }
    1327:   /* Create finite element */
    1328:   PetscFECreate(comm, fem);
    1329:   PetscFESetType(*fem, PETSCFEBASIC);
    1330:   PetscFESetNumComponents(*fem, Nc);
    1331:   PetscFESetBasisSpace(*fem, P);
    1332:   PetscFESetDualSpace(*fem, Q);
    1333:   PetscFESetQuadrature(*fem, q);
    1334:   PetscFESetFaceQuadrature(*fem, fq);
    1335:   if (prefix) {
    1336:     PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix);
    1337:     PetscFESetFromOptions(*fem);
    1338:     PetscObjectSetOptionsPrefix((PetscObject) *fem, NULL);
    1339:   }
    1340:   PetscFESetUp(*fem);
    1341:   /* Cleanup */
    1342:   PetscSpaceDestroy(&P);
    1343:   PetscDualSpaceDestroy(&Q);
    1344:   PetscQuadratureDestroy(&q);
    1345:   PetscQuadratureDestroy(&fq);
    1346:   /* Set finite element name */
    1347:   PetscSNPrintf(name, sizeof(name), "%s%D", isSimplex? "P" : "Q", k);
    1348:   PetscFESetName(*fem, name);
    1349:   return(0);
    1350: }

    1352: /*@C
    1353:   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file

    1355: + comm        - The MPI communicator
    1356: . filename    - Name of the Gmsh file
    1357: - interpolate - Create faces and edges in the mesh

    1359:   Output Parameter:
    1360: . dm  - The DM object representing the mesh

    1362:   Level: beginner

    1364: .seealso: DMPlexCreateFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
    1365: @*/
    1366: PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
    1367: {
    1368:   PetscViewer     viewer;
    1369:   PetscMPIInt     rank;
    1370:   int             fileType;
    1371:   PetscViewerType vtype;
    1372:   PetscErrorCode  ierr;

    1375:   MPI_Comm_rank(comm, &rank);

    1377:   /* Determine Gmsh file type (ASCII or binary) from file header */
    1378:   if (rank == 0) {
    1379:     GmshFile    gmsh[1];
    1380:     char        line[PETSC_MAX_PATH_LEN];
    1381:     int         snum;
    1382:     float       version;

    1384:     PetscArrayzero(gmsh,1);
    1385:     PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer);
    1386:     PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII);
    1387:     PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ);
    1388:     PetscViewerFileSetName(gmsh->viewer, filename);
    1389:     /* Read only the first two lines of the Gmsh file */
    1390:     GmshReadSection(gmsh, line);
    1391:     GmshExpect(gmsh, "$MeshFormat", line);
    1392:     GmshReadString(gmsh, line, 2);
    1393:     snum = sscanf(line, "%f %d", &version, &fileType);
    1394:     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
    1395:     if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
    1396:     if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
    1397:     if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
    1398:     PetscViewerDestroy(&gmsh->viewer);
    1399:   }
    1400:   MPI_Bcast(&fileType, 1, MPI_INT, 0, comm);
    1401:   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;

    1403:   /* Create appropriate viewer and build plex */
    1404:   PetscViewerCreate(comm, &viewer);
    1405:   PetscViewerSetType(viewer, vtype);
    1406:   PetscViewerFileSetMode(viewer, FILE_MODE_READ);
    1407:   PetscViewerFileSetName(viewer, filename);
    1408:   DMPlexCreateGmsh(comm, viewer, interpolate, dm);
    1409:   PetscViewerDestroy(&viewer);
    1410:   return(0);
    1411: }

    1413: /*@
    1414:   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer

    1416:   Collective

    1418:   Input Parameters:
    1419: + comm  - The MPI communicator
    1420: . viewer - The Viewer associated with a Gmsh file
    1421: - interpolate - Create faces and edges in the mesh

    1423:   Output Parameter:
    1424: . dm  - The DM object representing the mesh

    1426:   Note: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format

    1428:   Level: beginner

    1430: .seealso: DMPLEX, DMCreate()
    1431: @*/
    1432: PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
    1433: {
    1434:   GmshMesh      *mesh = NULL;
    1435:   PetscViewer    parentviewer = NULL;
    1436:   PetscBT        periodicVerts = NULL;
    1437:   PetscBT        periodicCells = NULL;
    1438:   DM             cdm;
    1439:   PetscSection   coordSection;
    1440:   Vec            coordinates;
    1441:   DMLabel        cellSets = NULL, faceSets = NULL, vertSets = NULL, marker = NULL;
    1442:   PetscInt       dim = 0, coordDim = -1, order = 0;
    1443:   PetscInt       numNodes = 0, numElems = 0, numVerts = 0, numCells = 0;
    1444:   PetscInt       cell, cone[8], e, n, v, d;
    1445:   PetscBool      binary, usemarker = PETSC_FALSE;
    1446:   PetscBool      hybrid = interpolate, periodic = PETSC_TRUE;
    1447:   PetscBool      highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
    1448:   PetscBool      isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
    1449:   PetscMPIInt    rank;

    1453:   MPI_Comm_rank(comm, &rank);
    1454:   PetscObjectOptionsBegin((PetscObject)viewer);
    1455:   PetscOptionsHead(PetscOptionsObject,"DMPlex Gmsh options");
    1456:   PetscOptionsBool("-dm_plex_gmsh_hybrid", "Generate hybrid cell bounds", "DMPlexCreateGmsh", hybrid, &hybrid, NULL);
    1457:   PetscOptionsBool("-dm_plex_gmsh_periodic","Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL);
    1458:   PetscOptionsBool("-dm_plex_gmsh_highorder","Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet);
    1459:   PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL);
    1460:   PetscOptionsBool("-dm_plex_gmsh_use_marker", "Generate marker label", "DMPlexCreateGmsh", usemarker, &usemarker, NULL);
    1461:   PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE);
    1462:   PetscOptionsTail();
    1463:   PetscOptionsEnd();

    1465:   GmshCellInfoSetUp();

    1467:   DMCreate(comm, dm);
    1468:   DMSetType(*dm, DMPLEX);
    1469:   PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);

    1471:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary);

    1473:   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
    1474:   if (binary) {
    1475:     parentviewer = viewer;
    1476:     PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);
    1477:   }

    1479:   if (rank == 0) {
    1480:     GmshFile  gmsh[1];
    1481:     char      line[PETSC_MAX_PATH_LEN];
    1482:     PetscBool match;

    1484:     PetscArrayzero(gmsh,1);
    1485:     gmsh->viewer = viewer;
    1486:     gmsh->binary = binary;

    1488:     GmshMeshCreate(&mesh);

    1490:     /* Read mesh format */
    1491:     GmshReadSection(gmsh, line);
    1492:     GmshExpect(gmsh, "$MeshFormat", line);
    1493:     GmshReadMeshFormat(gmsh);
    1494:     GmshReadEndSection(gmsh, "$EndMeshFormat", line);

    1496:     /* OPTIONAL Read physical names */
    1497:     GmshReadSection(gmsh, line);
    1498:     GmshMatch(gmsh, "$PhysicalNames", line, &match);
    1499:     if (match) {
    1500:       GmshExpect(gmsh, "$PhysicalNames", line);
    1501:       GmshReadPhysicalNames(gmsh);
    1502:       GmshReadEndSection(gmsh, "$EndPhysicalNames", line);
    1503:       /* Initial read for entity section */
    1504:       GmshReadSection(gmsh, line);
    1505:     }

    1507:     /* Read entities */
    1508:     if (gmsh->fileFormat >= 40) {
    1509:       GmshExpect(gmsh, "$Entities", line);
    1510:       GmshReadEntities(gmsh, mesh);
    1511:       GmshReadEndSection(gmsh, "$EndEntities", line);
    1512:       /* Initial read for nodes section */
    1513:       GmshReadSection(gmsh, line);
    1514:     }

    1516:     /* Read nodes */
    1517:     GmshExpect(gmsh, "$Nodes", line);
    1518:     GmshReadNodes(gmsh, mesh);
    1519:     GmshReadEndSection(gmsh, "$EndNodes", line);

    1521:     /* Read elements */
    1522:     GmshReadSection(gmsh, line);
    1523:     GmshExpect(gmsh, "$Elements", line);
    1524:     GmshReadElements(gmsh, mesh);
    1525:     GmshReadEndSection(gmsh, "$EndElements", line);

    1527:     /* Read periodic section (OPTIONAL) */
    1528:     if (periodic) {
    1529:       GmshReadSection(gmsh, line);
    1530:       GmshMatch(gmsh, "$Periodic", line, &periodic);
    1531:     }
    1532:     if (periodic) {
    1533:       GmshExpect(gmsh, "$Periodic", line);
    1534:       GmshReadPeriodic(gmsh, mesh);
    1535:       GmshReadEndSection(gmsh, "$EndPeriodic", line);
    1536:     }

    1538:     PetscFree(gmsh->wbuf);
    1539:     PetscFree(gmsh->sbuf);
    1540:     PetscFree(gmsh->nbuf);

    1542:     dim       = mesh->dim;
    1543:     order     = mesh->order;
    1544:     numNodes  = mesh->numNodes;
    1545:     numElems  = mesh->numElems;
    1546:     numVerts  = mesh->numVerts;
    1547:     numCells  = mesh->numCells;

    1549:     {
    1550:       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
    1551:       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1  : NULL;
    1552:       int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
    1553:       int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
    1554:       isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
    1555:       isHybrid  = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
    1556:       hasTetra  = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
    1557:     }
    1558:   }

    1560:   if (parentviewer) {
    1561:     PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);
    1562:   }

    1564:   {
    1565:     int buf[6];

    1567:     buf[0] = (int)dim;
    1568:     buf[1] = (int)order;
    1569:     buf[2] = periodic;
    1570:     buf[3] = isSimplex;
    1571:     buf[4] = isHybrid;
    1572:     buf[5] = hasTetra;

    1574:     MPI_Bcast(buf, 6, MPI_INT, 0, comm);

    1576:     dim       = buf[0];
    1577:     order     = buf[1];
    1578:     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
    1579:     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
    1580:     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
    1581:     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
    1582:   }

    1584:   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
    1585:   if (highOrder && isHybrid) SETERRQ(comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");

    1587:   /* We do not want this label automatically computed, instead we fill it here */
    1588:   DMCreateLabel(*dm, "celltype");

    1590:   /* Allocate the cell-vertex mesh */
    1591:   DMPlexSetChart(*dm, 0, numCells+numVerts);
    1592:   for (cell = 0; cell < numCells; ++cell) {
    1593:     GmshElement *elem = mesh->elements + cell;
    1594:     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
    1595:     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
    1596:     DMPlexSetConeSize(*dm, cell, elem->numVerts);
    1597:     DMPlexSetCellType(*dm, cell, ctype);
    1598:   }
    1599:   for (v = numCells; v < numCells+numVerts; ++v) {
    1600:     DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);
    1601:   }
    1602:   DMSetUp(*dm);

    1604:   /* Add cell-vertex connections */
    1605:   for (cell = 0; cell < numCells; ++cell) {
    1606:     GmshElement *elem = mesh->elements + cell;
    1607:     for (v = 0; v < elem->numVerts; ++v) {
    1608:       const PetscInt nn = elem->nodes[v];
    1609:       const PetscInt vv = mesh->vertexMap[nn];
    1610:       cone[v] = numCells + vv;
    1611:     }
    1612:     DMPlexReorderCell(*dm, cell, cone);
    1613:     DMPlexSetCone(*dm, cell, cone);
    1614:   }

    1616:   DMSetDimension(*dm, dim);
    1617:   DMPlexSymmetrize(*dm);
    1618:   DMPlexStratify(*dm);
    1619:   if (interpolate) {
    1620:     DM idm;

    1622:     DMPlexInterpolate(*dm, &idm);
    1623:     DMDestroy(dm);
    1624:     *dm  = idm;
    1625:   }

    1627:   if (usemarker && !interpolate && dim > 1) SETERRQ(comm,PETSC_ERR_SUP,"Cannot create marker label without interpolation");
    1628:   if (rank == 0 && usemarker) {
    1629:     PetscInt f, fStart, fEnd;

    1631:     DMCreateLabel(*dm, "marker");
    1632:     DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd);
    1633:     for (f = fStart; f < fEnd; ++f) {
    1634:       PetscInt suppSize;

    1636:       DMPlexGetSupportSize(*dm, f, &suppSize);
    1637:       if (suppSize == 1) {
    1638:         PetscInt *cone = NULL, coneSize, p;

    1640:         DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);
    1641:         for (p = 0; p < coneSize; p += 2) {
    1642:           DMSetLabelValue_Fast(*dm, &marker, "marker", cone[p], 1);
    1643:         }
    1644:         DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);
    1645:       }
    1646:     }
    1647:   }

    1649:   if (rank == 0) {
    1650:     PetscInt vStart, vEnd;

    1652:     DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);
    1653:     for (cell = 0, e = 0; e < numElems; ++e) {
    1654:       GmshElement *elem = mesh->elements + e;

    1656:       /* Create cell sets */
    1657:       if (elem->dim == dim && dim > 0) {
    1658:         if (elem->numTags > 0) {
    1659:           DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, elem->tags[0]);
    1660:         }
    1661:         cell++;
    1662:       }

    1664:       /* Create face sets */
    1665:       if (interpolate && elem->dim == dim-1) {
    1666:         PetscInt        joinSize;
    1667:         const PetscInt *join = NULL;
    1668:         /* Find the relevant facet with vertex joins */
    1669:         for (v = 0; v < elem->numVerts; ++v) {
    1670:           const PetscInt nn = elem->nodes[v];
    1671:           const PetscInt vv = mesh->vertexMap[nn];
    1672:           cone[v] = vStart + vv;
    1673:         }
    1674:         DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join);
    1675:         if (joinSize != 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %D (Plex cell %D)", elem->id, e);
    1676:         DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], elem->tags[0]);
    1677:         DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join);
    1678:       }

    1680:       /* Create vertex sets */
    1681:       if (elem->dim == 0) {
    1682:         if (elem->numTags > 0) {
    1683:           const PetscInt nn = elem->nodes[0];
    1684:           const PetscInt vv = mesh->vertexMap[nn];
    1685:           DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, elem->tags[0]);
    1686:         }
    1687:       }
    1688:     }
    1689:   }

    1691:   { /* Create Cell/Face/Vertex Sets labels at all processes */
    1692:     enum {n = 4};
    1693:     PetscBool flag[n];

    1695:     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
    1696:     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
    1697:     flag[2] = vertSets ? PETSC_TRUE : PETSC_FALSE;
    1698:     flag[3] = marker   ? PETSC_TRUE : PETSC_FALSE;
    1699:     MPI_Bcast(flag, n, MPIU_BOOL, 0, comm);
    1700:     if (flag[0]) {DMCreateLabel(*dm, "Cell Sets");}
    1701:     if (flag[1]) {DMCreateLabel(*dm, "Face Sets");}
    1702:     if (flag[2]) {DMCreateLabel(*dm, "Vertex Sets");}
    1703:     if (flag[3]) {DMCreateLabel(*dm, "marker");}
    1704:   }

    1706:   if (periodic) {
    1707:     PetscBTCreate(numVerts, &periodicVerts);
    1708:     for (n = 0; n < numNodes; ++n) {
    1709:       if (mesh->vertexMap[n] >= 0) {
    1710:         if (PetscUnlikely(mesh->periodMap[n] != n)) {
    1711:           PetscInt m = mesh->periodMap[n];
    1712:           PetscBTSet(periodicVerts, mesh->vertexMap[n]);
    1713:           PetscBTSet(periodicVerts, mesh->vertexMap[m]);
    1714:         }
    1715:       }
    1716:     }
    1717:     PetscBTCreate(numCells, &periodicCells);
    1718:     for (cell = 0; cell < numCells; ++cell) {
    1719:       GmshElement *elem = mesh->elements + cell;
    1720:       for (v = 0; v < elem->numVerts; ++v) {
    1721:         PetscInt nn = elem->nodes[v];
    1722:         PetscInt vv = mesh->vertexMap[nn];
    1723:         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
    1724:           PetscBTSet(periodicCells, cell); break;
    1725:         }
    1726:       }
    1727:     }
    1728:   }

    1730:   /* Setup coordinate DM */
    1731:   if (coordDim < 0) coordDim = dim;
    1732:   DMSetCoordinateDim(*dm, coordDim);
    1733:   DMGetCoordinateDM(*dm, &cdm);
    1734:   if (highOrder) {
    1735:     PetscFE         fe;
    1736:     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
    1737:     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;

    1739:     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */

    1741:     GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);
    1742:     PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view");
    1743:     DMSetField(cdm, 0, NULL, (PetscObject) fe);
    1744:     PetscFEDestroy(&fe);
    1745:     DMCreateDS(cdm);
    1746:   }

    1748:   /* Create coordinates */
    1749:   if (highOrder) {

    1751:     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
    1752:     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
    1753:     PetscSection section;
    1754:     PetscScalar  *cellCoords;

    1756:     DMSetLocalSection(cdm, NULL);
    1757:     DMGetLocalSection(cdm, &coordSection);
    1758:     PetscSectionClone(coordSection, &section);
    1759:     DMPlexSetClosurePermutationTensor(cdm, 0, section); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */

    1761:     DMCreateLocalVector(cdm, &coordinates);
    1762:     PetscMalloc1(maxDof, &cellCoords);
    1763:     for (cell = 0; cell < numCells; ++cell) {
    1764:       GmshElement *elem = mesh->elements + cell;
    1765:       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
    1766:       for (n = 0; n < elem->numNodes; ++n) {
    1767:         const PetscInt node = elem->nodes[lexorder[n]];
    1768:         for (d = 0; d < coordDim; ++d)
    1769:           cellCoords[n*coordDim+d] = (PetscReal) coords[node*3+d];
    1770:       }
    1771:       DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES);
    1772:     }
    1773:     PetscSectionDestroy(&section);
    1774:     PetscFree(cellCoords);

    1776:   } else {

    1778:     PetscInt    *nodeMap;
    1779:     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
    1780:     PetscScalar *pointCoords;

    1782:     DMGetLocalSection(cdm, &coordSection);
    1783:     PetscSectionSetNumFields(coordSection, 1);
    1784:     PetscSectionSetFieldComponents(coordSection, 0, coordDim);
    1785:     if (periodic) { /* we need to localize coordinates on cells */
    1786:       PetscSectionSetChart(coordSection, 0, numCells+numVerts);
    1787:     } else {
    1788:       PetscSectionSetChart(coordSection, numCells, numCells+numVerts);
    1789:     }
    1790:     if (periodic) {
    1791:       for (cell = 0; cell < numCells; ++cell) {
    1792:         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
    1793:           GmshElement *elem = mesh->elements + cell;
    1794:           PetscInt dof = elem->numVerts * coordDim;
    1795:           PetscSectionSetDof(coordSection, cell, dof);
    1796:           PetscSectionSetFieldDof(coordSection, cell, 0, dof);
    1797:         }
    1798:       }
    1799:     }
    1800:     for (v = numCells; v < numCells+numVerts; ++v) {
    1801:       PetscSectionSetDof(coordSection, v, coordDim);
    1802:       PetscSectionSetFieldDof(coordSection, v, 0, coordDim);
    1803:     }
    1804:     PetscSectionSetUp(coordSection);

    1806:     DMCreateLocalVector(cdm, &coordinates);
    1807:     VecGetArray(coordinates, &pointCoords);
    1808:     if (periodic) {
    1809:       for (cell = 0; cell < numCells; ++cell) {
    1810:         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
    1811:           GmshElement *elem = mesh->elements + cell;
    1812:           PetscInt off, node;
    1813:           for (v = 0; v < elem->numVerts; ++v)
    1814:             cone[v] = elem->nodes[v];
    1815:           DMPlexReorderCell(cdm, cell, cone);
    1816:           PetscSectionGetOffset(coordSection, cell, &off);
    1817:           for (v = 0; v < elem->numVerts; ++v)
    1818:             for (node = cone[v], d = 0; d < coordDim; ++d)
    1819:               pointCoords[off++] = (PetscReal) coords[node*3+d];
    1820:         }
    1821:       }
    1822:     }
    1823:     PetscMalloc1(numVerts, &nodeMap);
    1824:     for (n = 0; n < numNodes; n++)
    1825:       if (mesh->vertexMap[n] >= 0)
    1826:         nodeMap[mesh->vertexMap[n]] = n;
    1827:     for (v = 0; v < numVerts; ++v) {
    1828:       PetscInt off, node = nodeMap[v];
    1829:       PetscSectionGetOffset(coordSection, numCells + v, &off);
    1830:       for (d = 0; d < coordDim; ++d)
    1831:         pointCoords[off+d] = (PetscReal) coords[node*3+d];
    1832:     }
    1833:     PetscFree(nodeMap);
    1834:     VecRestoreArray(coordinates, &pointCoords);

    1836:   }

    1838:   PetscObjectSetName((PetscObject) coordinates, "coordinates");
    1839:   VecSetBlockSize(coordinates, coordDim);
    1840:   DMSetCoordinatesLocal(*dm, coordinates);
    1841:   VecDestroy(&coordinates);
    1842:   DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL);

    1844:   GmshMeshDestroy(&mesh);
    1845:   PetscBTDestroy(&periodicVerts);
    1846:   PetscBTDestroy(&periodicCells);

    1848:   if (highOrder && project)  {
    1849:     PetscFE         fe;
    1850:     const char      prefix[]   = "dm_plex_gmsh_project_";
    1851:     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
    1852:     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;

    1854:     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */

    1856:     GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);
    1857:     PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view");
    1858:     DMProjectCoordinates(*dm, fe);
    1859:     PetscFEDestroy(&fe);
    1860:   }

    1862:   PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);
    1863:   return(0);
    1864: }