xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 44b85a236d0c752951b0573ba76bfb3134d48c1e)
1 #define PETSCDM_DLL
2 #include <petsc-private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "DMPlexCreateGmsh"
6 /*@
7   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file.
8 
9   Collective on comm
10 
11   Input Parameters:
12 + comm  - The MPI communicator
13 . viewer - The Viewer associated with a Gmsh file
14 - interpolate - Create faces and edges in the mesh
15 
16   Output Parameter:
17 . dm  - The DM object representing the mesh
18 
19   Note: http://www.geuz.org/gmsh/doc/texinfo/#MSH-ASCII-file-format
20 
21   Level: beginner
22 
23 .keywords: mesh,Gmsh
24 .seealso: DMPLEX, DMCreate()
25 @*/
26 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
27 {
28   FILE          *fd;
29   PetscSection   coordSection;
30   Vec            coordinates;
31   PetscScalar   *coords, *coordsIn = NULL;
32   PetscInt       dim = 0, tdim = 0, coordSize, c, v, d, numCorners;
33   int            numVertices = 0, numCells = 0, trueNumCells = 0, numFacets = 0, cone[8], tags[2], cellNum, snum;
34   long           fpos = 0;
35   PetscMPIInt    num_proc, rank;
36   char           line[PETSC_MAX_PATH_LEN];
37   PetscBool      match;
38   PetscErrorCode ierr;
39 
40   PetscFunctionBegin;
41   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
42   ierr = MPI_Comm_size(comm, &num_proc);CHKERRQ(ierr);
43   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
44   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
45   if (!rank) {
46     PetscBool match;
47     int       fileType, dataSize;
48 
49     ierr = PetscViewerASCIIGetPointer(viewer, &fd);CHKERRQ(ierr);
50     /* Read header */
51     fgets(line, PETSC_MAX_PATH_LEN, fd);
52     ierr = PetscStrncmp(line, "$MeshFormat\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
53     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
54     snum = fscanf(fd, "2.2 %d %d\n", &fileType, &dataSize);CHKERRQ(snum != 2);
55     if (fileType) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File type %d is not a valid Gmsh ASCII file", fileType);
56     if (dataSize != sizeof(double)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data size %d is not valid for a Gmsh file", dataSize);
57     fgets(line, PETSC_MAX_PATH_LEN, fd);
58     ierr = PetscStrncmp(line, "$EndMeshFormat\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
59     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
60     /* Read vertices */
61     fgets(line, PETSC_MAX_PATH_LEN, fd);
62     ierr = PetscStrncmp(line, "$Nodes\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
63     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
64     snum = fscanf(fd, "%d\n", &numVertices);CHKERRQ(snum != 1);
65     ierr = PetscMalloc(numVertices*3 * sizeof(PetscScalar), &coordsIn);CHKERRQ(ierr);
66     for (v = 0; v < numVertices; ++v) {
67       double x, y, z;
68       int    i;
69 
70       snum = fscanf(fd, "%d %lg %lg %lg\n", &i, &x, &y, &z);CHKERRQ(snum != 4);
71       coordsIn[v*3+0] = x; coordsIn[v*3+1] = y; coordsIn[v*3+2] = z;
72       if (i != v+1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid node number %d should be %d", i, v+1);
73     }
74     fgets(line, PETSC_MAX_PATH_LEN, fd);
75     ierr = PetscStrncmp(line, "$EndNodes\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
76     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
77     /* Read cells */
78     fgets(line, PETSC_MAX_PATH_LEN, fd);
79     ierr = PetscStrncmp(line, "$Elements\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
80     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
81     snum = fscanf(fd, "%d\n", &numCells);CHKERRQ(snum != 1);
82   }
83 
84   if (!rank) {
85     fpos = ftell(fd);
86     /* The Gmsh format disguises facets as elements, so we have to run through all "element" entries
87        to get the correct numCells and decide the topological dimension of the mesh */
88     trueNumCells = 0;
89     for (c = 0; c < numCells; ++c) {
90       ierr = DMPlexCreateGmsh_ReadElement(fd, &dim, &cellNum, &numCorners, cone, tags);CHKERRQ(ierr);
91       if (dim > tdim) {
92         tdim = dim;
93         trueNumCells = 0;
94       }
95       trueNumCells++;
96     }
97   }
98   ierr = DMPlexSetChart(*dm, 0, trueNumCells+numVertices);CHKERRQ(ierr);
99   numFacets = numCells - trueNumCells;
100   if (!rank) {
101     ierr = fseek(fd, fpos, SEEK_SET);CHKERRQ(ierr);
102     for (c = 0; c < numCells; ++c) {
103       ierr = DMPlexCreateGmsh_ReadElement(fd, &dim, &cellNum, &numCorners, cone, tags);CHKERRQ(ierr);
104       if (dim == tdim) {
105         ierr = DMPlexSetConeSize(*dm, c-numFacets, numCorners);CHKERRQ(ierr);
106       }
107       if (cellNum != c+1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid cell number %d should be %d", cellNum, c+1);
108     }
109   }
110   ierr = DMSetUp(*dm);CHKERRQ(ierr);
111   if (!rank) {
112     PetscInt pcone[8], corner;
113 
114     ierr = fseek(fd, fpos, SEEK_SET);CHKERRQ(ierr);
115     for (c = 0; c < numCells; ++c) {
116       ierr = DMPlexCreateGmsh_ReadElement(fd, &dim, &cellNum, &numCorners, cone, tags);CHKERRQ(ierr);
117       if (dim == tdim) {
118         for (corner = 0; corner < numCorners; ++corner) pcone[corner] = cone[corner] + trueNumCells-1;
119         ierr = DMPlexSetCone(*dm, c-numFacets, (const PetscInt *) pcone);CHKERRQ(ierr);
120       }
121       if (cellNum != c+1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid cell number %d should be %d", cellNum, c+1);
122     }
123     fgets(line, PETSC_MAX_PATH_LEN, fd);
124     ierr = PetscStrncmp(line, "$EndElements\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
125     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
126   }
127   ierr = MPI_Bcast(&dim, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
128   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
129   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
130   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
131   if (interpolate) {
132     DM idm = NULL;
133 
134     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
135     ierr = DMDestroy(dm);CHKERRQ(ierr);
136     *dm  = idm;
137   }
138 
139   if (!rank) {
140     /* Apply boundary IDs by finding the relevant facets with vertex joins */
141     PetscInt pcone[8], corner, vStart, vEnd;
142 
143     ierr = fseek(fd, fpos, SEEK_SET);CHKERRQ(ierr);
144     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
145     for (c = 0; c < numCells; ++c) {
146       ierr = DMPlexCreateGmsh_ReadElement(fd, &dim, &cellNum, &numCorners, cone, tags);CHKERRQ(ierr);
147       if (dim == tdim-1) {
148         PetscInt joinSize;
149         const PetscInt *join;
150         for (corner = 0; corner < numCorners; ++corner) pcone[corner] = cone[corner] + vStart - 1;
151         ierr = DMPlexGetFullJoin(*dm, numCorners, (const PetscInt *) pcone, &joinSize, &join);CHKERRQ(ierr);
152         if (joinSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not determine Plex facet for element %d", cellNum);
153         ierr = DMPlexSetLabelValue(*dm, "Face Sets", join[0], tags[0]);CHKERRQ(ierr);
154         ierr = DMPlexRestoreJoin(*dm, numCorners, (const PetscInt *) pcone, &joinSize, &join);CHKERRQ(ierr);
155       }
156       if (cellNum != c+1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid cell number %d should be %d", cellNum, c+1);
157     }
158     fgets(line, PETSC_MAX_PATH_LEN, fd);
159     ierr = PetscStrncmp(line, "$EndElements\n", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
160     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
161   }
162 
163   /* Read coordinates */
164   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
165   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
166   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
167   ierr = PetscSectionSetChart(coordSection, trueNumCells, trueNumCells + numVertices);CHKERRQ(ierr);
168   for (v = trueNumCells; v < trueNumCells+numVertices; ++v) {
169     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
170     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
171   }
172   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
173   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
174   ierr = VecCreate(comm, &coordinates);CHKERRQ(ierr);
175   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
176   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
177   ierr = VecSetType(coordinates, VECSTANDARD);CHKERRQ(ierr);
178   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
179   if (!rank) {
180     for (v = 0; v < numVertices; ++v) {
181       for (d = 0; d < dim; ++d) {
182         coords[v*dim+d] = coordsIn[v*3+d];
183       }
184     }
185   }
186   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
187   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
188   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
189   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
190   PetscFunctionReturn(0);
191 }
192 
193 #undef __FUNCT__
194 #define __FUNCT__ "DMPlexCreateGmsh_ReadElement"
195 PetscErrorCode DMPlexCreateGmsh_ReadElement(FILE *fd, PetscInt *dim, int *cellNum, PetscInt *numCorners, int cone[], int tags[])
196 {
197   PetscInt t;
198   int      numTags, snum, cellType;
199 
200   PetscFunctionBegin;
201   snum = fscanf(fd, "%d %d %d", cellNum, &cellType, &numTags);CHKERRQ(snum != 3);
202   for (t = 0; t < numTags; ++t) {snum = fscanf(fd, "%d", &tags[t]);CHKERRQ(snum != 1);}
203   switch (cellType) {
204   case 1: /* 2-node line */
205     *dim = 1;
206     *numCorners = 2;
207     snum = fscanf(fd, "%d %d\n", &cone[0], &cone[1]);CHKERRQ(snum != *numCorners);
208     break;
209   case 2: /* 3-node triangle */
210     *dim = 2;
211     *numCorners = 3;
212     snum = fscanf(fd, "%d %d %d\n", &cone[0], &cone[1], &cone[2]);CHKERRQ(snum != *numCorners);
213     break;
214   case 3: /* 4-node quadrangle */
215     *dim = 2;
216     *numCorners = 4;
217     snum = fscanf(fd, "%d %d %d %d\n", &cone[0], &cone[1], &cone[2], &cone[3]);CHKERRQ(snum != *numCorners);
218     break;
219   case 4: /* 4-node tetrahedron */
220     *dim  = 3;
221     *numCorners = 4;
222     snum = fscanf(fd, "%d %d %d %d\n", &cone[0], &cone[1], &cone[2], &cone[3]);CHKERRQ(snum != *numCorners);
223     break;
224   case 5: /* 8-node hexahedron */
225     *dim = 3;
226     *numCorners = 8;
227     snum = fscanf(fd, "%d %d %d %d %d %d %d %d\n", &cone[0], &cone[1], &cone[2], &cone[3], &cone[4], &cone[5], &cone[6], &cone[7]);CHKERRQ(snum != *numCorners);
228     break;
229   case 15: /* 1-node vertex */
230     *dim = 0;
231     *numCorners = 1;
232     snum = fscanf(fd, "%d\n", &cone[0]);CHKERRQ(snum != *numCorners);
233     break;
234   default:
235     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported Gmsh element type %d", cellType);
236   }
237   PetscFunctionReturn(0);
238 }
239