xref: /petsc/src/dm/impls/plex/adaptors/mmg/mmgadapt.c (revision c3b5f7ba6bc5ce25a01a67bb37ba5d34b02bbbd7)
1 #include "../mmgcommon.h"   /*I      "petscdmplex.h"   I*/
2 #include <mmg/libmmg.h>
3 
4 PETSC_EXTERN PetscErrorCode DMAdaptMetric_Mmg_Plex(DM dm, Vec vertexMetric, DMLabel bdLabel, DMLabel rgLabel, DM *dmNew)
5 {
6   MPI_Comm           comm;
7   const char        *bdName = "_boundary_";
8   const char        *rgName = "_regions_";
9   DM                 udm, cdm;
10   DMLabel            bdLabelNew, rgLabelNew;
11   const char        *bdLabelName, *rgLabelName;
12   PetscSection       coordSection;
13   Vec                coordinates;
14   const PetscScalar *coords, *met;
15   PetscReal         *vertices, *metric, *verticesNew, gradationFactor, hausdorffNumber;
16   PetscInt          *cells, *cellsNew, *cellTags, *cellTagsNew, *verTags, *verTagsNew;
17   PetscInt          *bdFaces, *faceTags, *facesNew, *faceTagsNew;
18   PetscInt          *corners, *requiredCells, *requiredVer, *ridges, *requiredFaces;
19   PetscInt           cStart, cEnd, c, numCells, fStart, fEnd, numFaceTags, f, vStart, vEnd, v, numVertices;
20   PetscInt           dim, off, coff, maxConeSize, bdSize, i, j, k, Neq, verbosity, pStart, pEnd;
21   PetscInt           numCellsNew, numVerticesNew, numCornersNew, numFacesNew;
22   PetscBool          flg = PETSC_FALSE, noInsert, noSwap, noMove, noSurf, isotropic, uniform;
23   MMG5_pMesh         mmg_mesh = NULL;
24   MMG5_pSol          mmg_metric = NULL;
25 
26   PetscFunctionBegin;
27   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
28   if (bdLabel) {
29     PetscCall(PetscObjectGetName((PetscObject) bdLabel, &bdLabelName));
30     PetscCall(PetscStrcmp(bdLabelName, bdName, &flg));
31     PetscCheck(!flg,comm, PETSC_ERR_ARG_WRONG, "\"%s\" cannot be used as label for boundary facets", bdLabelName);
32   }
33   if (rgLabel) {
34     PetscCall(PetscObjectGetName((PetscObject) rgLabel, &rgLabelName));
35     PetscCall(PetscStrcmp(rgLabelName, rgName, &flg));
36     PetscCheck(!flg,comm, PETSC_ERR_ARG_WRONG, "\"%s\" cannot be used as label for element tags", rgLabelName);
37   }
38 
39   /* Get mesh information */
40   PetscCall(DMGetDimension(dm, &dim));
41   Neq  = (dim*(dim+1))/2;
42   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
43   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
44   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
45   PetscCall(DMPlexUninterpolate(dm, &udm));
46   PetscCall(DMPlexGetMaxSizes(udm, &maxConeSize, NULL));
47   numCells    = cEnd - cStart;
48   numVertices = vEnd - vStart;
49 
50   /* Get cell offsets */
51   PetscCall(PetscMalloc1(numCells*maxConeSize, &cells));
52   for (c = 0, coff = 0; c < numCells; ++c) {
53     const PetscInt *cone;
54     PetscInt        coneSize, cl;
55 
56     PetscCall(DMPlexGetConeSize(udm, c, &coneSize));
57     PetscCall(DMPlexGetCone(udm, c, &cone));
58     for (cl = 0; cl < coneSize; ++cl) cells[coff++] = cone[cl] - vStart + 1;
59   }
60 
61   /* Get vertex coordinate array */
62   PetscCall(DMGetCoordinateDM(dm, &cdm));
63   PetscCall(DMGetLocalSection(cdm, &coordSection));
64   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
65   PetscCall(VecGetArrayRead(coordinates, &coords));
66   PetscCall(PetscMalloc2(numVertices*Neq, &metric, dim*numVertices, &vertices));
67   for (v = 0; v < vEnd-vStart; ++v) {
68     PetscCall(PetscSectionGetOffset(coordSection, v+vStart, &off));
69     for (i = 0; i < dim; ++i) vertices[dim*v+i] = PetscRealPart(coords[off+i]);
70   }
71   PetscCall(VecRestoreArrayRead(coordinates, &coords));
72   PetscCall(DMDestroy(&udm));
73 
74   /* Get face tags */
75   if (!bdLabel) {
76     flg = PETSC_TRUE;
77     PetscCall(DMLabelCreate(PETSC_COMM_SELF, bdName, &bdLabel));
78     PetscCall(DMPlexMarkBoundaryFaces(dm, 1, bdLabel));
79   }
80   PetscCall(DMLabelGetBounds(bdLabel, &pStart, &pEnd));
81   for (f = pStart, bdSize = 0, numFaceTags = 0; f < pEnd; ++f) {
82     PetscBool hasPoint;
83     PetscInt *closure = NULL, closureSize, cl;
84 
85     PetscCall(DMLabelHasPoint(bdLabel, f, &hasPoint));
86     if ((!hasPoint) || (f < fStart) || (f >= fEnd)) continue;
87     numFaceTags++;
88 
89     PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure));
90     for (cl = 0; cl < closureSize*2; cl += 2) {
91       if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) ++bdSize;
92     }
93     PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure));
94   }
95   PetscCall(PetscMalloc2(bdSize, &bdFaces, numFaceTags, &faceTags));
96   for (f = pStart, bdSize = 0, numFaceTags = 0; f < pEnd; ++f) {
97     PetscBool hasPoint;
98     PetscInt *closure = NULL, closureSize, cl;
99 
100     PetscCall(DMLabelHasPoint(bdLabel, f, &hasPoint));
101     if ((!hasPoint) || (f < fStart) || (f >= fEnd)) continue;
102 
103     PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure));
104     for (cl = 0; cl < closureSize*2; cl += 2) {
105       if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) bdFaces[bdSize++] = closure[cl] - vStart + 1;
106     }
107     PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure));
108     PetscCall(DMLabelGetValue(bdLabel, f, &faceTags[numFaceTags++]));
109   }
110   if (flg) PetscCall(DMLabelDestroy(&bdLabel));
111 
112   /* Get cell tags */
113   PetscCall(PetscCalloc2(numVertices, &verTags, numCells, &cellTags));
114   if (rgLabel) {
115     for (c = cStart; c < cEnd; ++c) PetscCall(DMLabelGetValue(rgLabel, c, &cellTags[c]));
116   }
117 
118   /* Get metric */
119   PetscCall(VecViewFromOptions(vertexMetric, NULL, "-adapt_metric_view"));
120   PetscCall(VecGetArrayRead(vertexMetric, &met));
121   PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic));
122   PetscCall(DMPlexMetricIsUniform(dm, &uniform));
123   for (v = 0; v < (vEnd-vStart); ++v) {
124     for (i = 0, k = 0; i < dim; ++i) {
125       for (j = i; j < dim; ++j) {
126         if (isotropic) {
127           if (i == j) {
128             if (uniform) metric[Neq*v+k] = PetscRealPart(met[0]);
129             else metric[Neq*v+k] = PetscRealPart(met[v]);
130           } else metric[Neq*v+k] = 0.0;
131         } else {
132           metric[Neq*v+k] = PetscRealPart(met[dim*dim*v+dim*i+j]);
133         }
134         k++;
135       }
136     }
137   }
138   PetscCall(VecRestoreArrayRead(vertexMetric, &met));
139 
140   /* Send mesh to Mmg and remesh */
141   PetscCall(DMPlexMetricGetVerbosity(dm, &verbosity));
142   PetscCall(DMPlexMetricGetGradationFactor(dm, &gradationFactor));
143   PetscCall(DMPlexMetricGetHausdorffNumber(dm, &hausdorffNumber));
144   PetscCall(DMPlexMetricNoInsertion(dm, &noInsert));
145   PetscCall(DMPlexMetricNoSwapping(dm, &noSwap));
146   PetscCall(DMPlexMetricNoMovement(dm, &noMove));
147   PetscCall(DMPlexMetricNoSurf(dm, &noSurf));
148   switch (dim) {
149   case 2:
150     PetscCallMMG_NONSTANDARD(MMG2D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg_mesh, MMG5_ARG_ppMet, &mmg_metric, MMG5_ARG_end));
151     PetscCallMMG_NONSTANDARD(MMG2D_Set_iparameter(mmg_mesh, mmg_metric, MMG2D_IPARAM_noinsert, noInsert));
152     PetscCallMMG_NONSTANDARD(MMG2D_Set_iparameter(mmg_mesh, mmg_metric, MMG2D_IPARAM_noswap, noSwap));
153     PetscCallMMG_NONSTANDARD(MMG2D_Set_iparameter(mmg_mesh, mmg_metric, MMG2D_IPARAM_nomove, noMove));
154     PetscCallMMG_NONSTANDARD(MMG2D_Set_iparameter(mmg_mesh, mmg_metric, MMG2D_IPARAM_nosurf, noSurf));
155     PetscCallMMG_NONSTANDARD(MMG2D_Set_iparameter(mmg_mesh, mmg_metric, MMG2D_IPARAM_verbose, verbosity));
156     PetscCallMMG_NONSTANDARD(MMG2D_Set_dparameter(mmg_mesh, mmg_metric, MMG2D_DPARAM_hgrad, gradationFactor));
157     PetscCallMMG_NONSTANDARD(MMG2D_Set_dparameter(mmg_mesh, mmg_metric, MMG2D_DPARAM_hausd, hausdorffNumber));
158     PetscCallMMG_NONSTANDARD(MMG2D_Set_meshSize(mmg_mesh, numVertices, numCells, 0, numFaceTags));
159     PetscCallMMG_NONSTANDARD(MMG2D_Set_vertices(mmg_mesh, vertices, verTags));
160     PetscCallMMG_NONSTANDARD(MMG2D_Set_triangles(mmg_mesh, cells, cellTags));
161     PetscCallMMG_NONSTANDARD(MMG2D_Set_edges(mmg_mesh, bdFaces, faceTags));
162     PetscCallMMG_NONSTANDARD(MMG2D_Set_solSize(mmg_mesh, mmg_metric, MMG5_Vertex, numVertices, MMG5_Tensor));
163     PetscCallMMG_NONSTANDARD(MMG2D_Set_tensorSols(mmg_metric, metric));
164     PetscCallMMG(MMG2D_mmg2dlib(mmg_mesh, mmg_metric));
165     break;
166   case 3:
167     PetscCallMMG_NONSTANDARD(MMG3D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg_mesh, MMG5_ARG_ppMet, &mmg_metric, MMG5_ARG_end));
168     PetscCallMMG_NONSTANDARD(MMG3D_Set_iparameter(mmg_mesh, mmg_metric, MMG3D_IPARAM_noinsert, noInsert));
169     PetscCallMMG_NONSTANDARD(MMG3D_Set_iparameter(mmg_mesh, mmg_metric, MMG3D_IPARAM_noswap, noSwap));
170     PetscCallMMG_NONSTANDARD(MMG3D_Set_iparameter(mmg_mesh, mmg_metric, MMG3D_IPARAM_nomove, noMove));
171     PetscCallMMG_NONSTANDARD(MMG3D_Set_iparameter(mmg_mesh, mmg_metric, MMG3D_IPARAM_nosurf, noSurf));
172     PetscCallMMG_NONSTANDARD(MMG3D_Set_iparameter(mmg_mesh, mmg_metric, MMG3D_IPARAM_verbose, verbosity));
173     PetscCallMMG_NONSTANDARD(MMG3D_Set_dparameter(mmg_mesh, mmg_metric, MMG3D_DPARAM_hgrad, gradationFactor));
174     PetscCallMMG_NONSTANDARD(MMG3D_Set_dparameter(mmg_mesh, mmg_metric, MMG3D_DPARAM_hausd, hausdorffNumber));
175     PetscCallMMG_NONSTANDARD(MMG3D_Set_meshSize(mmg_mesh, numVertices, numCells, 0, numFaceTags, 0, 0));
176     PetscCallMMG_NONSTANDARD(MMG3D_Set_vertices(mmg_mesh, vertices, verTags));
177     PetscCallMMG_NONSTANDARD(MMG3D_Set_tetrahedra(mmg_mesh, cells, cellTags));
178     PetscCallMMG_NONSTANDARD(MMG3D_Set_triangles(mmg_mesh, bdFaces, faceTags));
179     PetscCallMMG_NONSTANDARD(MMG3D_Set_solSize(mmg_mesh, mmg_metric, MMG5_Vertex, numVertices, MMG5_Tensor));
180     PetscCallMMG_NONSTANDARD(MMG3D_Set_tensorSols(mmg_metric, metric));
181     PetscCallMMG(MMG3D_mmg3dlib(mmg_mesh, mmg_metric));
182     break;
183   default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No Mmg adaptation defined for dimension %" PetscInt_FMT, dim);
184   }
185   PetscCall(PetscFree(cells));
186   PetscCall(PetscFree2(metric, vertices));
187   PetscCall(PetscFree2(bdFaces, faceTags));
188   PetscCall(PetscFree2(verTags, cellTags));
189 
190   /* Retrieve mesh from Mmg */
191   switch (dim) {
192   case 2:
193     numCornersNew = 3;
194     PetscCallMMG_NONSTANDARD(MMG2D_Get_meshSize(mmg_mesh, &numVerticesNew, &numCellsNew, 0, &numFacesNew));
195     PetscCall(PetscMalloc4(2*numVerticesNew, &verticesNew, numVerticesNew, &verTagsNew, numVerticesNew, &corners, numVerticesNew, &requiredVer));
196     PetscCall(PetscMalloc3(3*numCellsNew, &cellsNew, numCellsNew, &cellTagsNew, numCellsNew, &requiredCells));
197     PetscCall(PetscMalloc4(2*numFacesNew, &facesNew, numFacesNew, &faceTagsNew, numFacesNew, &ridges, numFacesNew, &requiredFaces));
198     PetscCallMMG_NONSTANDARD(MMG2D_Get_vertices(mmg_mesh, verticesNew, verTagsNew, corners, requiredVer));
199     PetscCallMMG_NONSTANDARD(MMG2D_Get_triangles(mmg_mesh, cellsNew, cellTagsNew, requiredCells));
200     PetscCallMMG_NONSTANDARD(MMG2D_Get_edges(mmg_mesh, facesNew, faceTagsNew, ridges, requiredFaces));
201     break;
202   case 3:
203     numCornersNew = 4;
204     PetscCallMMG_NONSTANDARD(MMG3D_Get_meshSize(mmg_mesh, &numVerticesNew, &numCellsNew, 0, &numFacesNew, 0, 0));
205     PetscCall(PetscMalloc4(3*numVerticesNew, &verticesNew, numVerticesNew, &verTagsNew, numVerticesNew, &corners, numVerticesNew, &requiredVer));
206     PetscCall(PetscMalloc3(4*numCellsNew, &cellsNew, numCellsNew, &cellTagsNew, numCellsNew, &requiredCells));
207     PetscCall(PetscMalloc4(3*numFacesNew, &facesNew, numFacesNew, &faceTagsNew, numFacesNew, &ridges, numFacesNew, &requiredFaces));
208     PetscCallMMG_NONSTANDARD(MMG3D_Get_vertices(mmg_mesh, verticesNew, verTagsNew, corners, requiredVer));
209     PetscCallMMG_NONSTANDARD(MMG3D_Get_tetrahedra(mmg_mesh, cellsNew, cellTagsNew, requiredCells));
210     PetscCallMMG_NONSTANDARD(MMG3D_Get_triangles(mmg_mesh, facesNew, faceTagsNew, requiredFaces));
211 
212     /* Reorder for consistency with DMPlex */
213     for (i = 0; i < numCellsNew; ++i) PetscCall(DMPlexInvertCell(DM_POLYTOPE_TETRAHEDRON, &cellsNew[4*i]));
214     break;
215 
216   default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No Mmg adaptation defined for dimension %" PetscInt_FMT, dim);
217   }
218 
219   /* Create new Plex */
220   for (i = 0; i < (dim+1)*numCellsNew; i++) cellsNew[i] -= 1;
221   for (i = 0; i < dim*numFacesNew; i++) facesNew[i] -= 1;
222   PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, dim, numCellsNew, numVerticesNew, PETSC_DECIDE, numCornersNew, PETSC_TRUE, cellsNew, dim, verticesNew, NULL, NULL, dmNew));
223   switch (dim) {
224   case 2:
225     PetscCallMMG_NONSTANDARD(MMG2D_Free_all(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg_mesh, MMG5_ARG_ppMet, &mmg_metric, MMG5_ARG_end));
226     break;
227   case 3:
228     PetscCallMMG_NONSTANDARD(MMG3D_Free_all(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg_mesh, MMG5_ARG_ppMet, &mmg_metric, MMG5_ARG_end));
229     break;
230   default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No Mmg adaptation defined for dimension %" PetscInt_FMT, dim);
231   }
232   PetscCall(PetscFree4(verticesNew, verTagsNew, corners, requiredVer));
233 
234   /* Get adapted mesh information */
235   PetscCall(DMPlexGetHeightStratum(*dmNew, 0, &cStart, &cEnd));
236   PetscCall(DMPlexGetHeightStratum(*dmNew, 1, &fStart, &fEnd));
237   PetscCall(DMPlexGetDepthStratum(*dmNew, 0, &vStart, &vEnd));
238 
239   /* Rebuild boundary labels */
240   PetscCall(DMCreateLabel(*dmNew, flg ? bdName : bdLabelName));
241   PetscCall(DMGetLabel(*dmNew, flg ? bdName : bdLabelName, &bdLabelNew));
242   for (i = 0; i < numFacesNew; i++) {
243     PetscInt        numCoveredPoints, numFaces = 0, facePoints[3];
244     const PetscInt *coveredPoints = NULL;
245 
246     for (j = 0; j < dim; ++j) facePoints[j] = facesNew[i*dim+j]+vStart;
247     PetscCall(DMPlexGetFullJoin(*dmNew, dim, facePoints, &numCoveredPoints, &coveredPoints));
248     for (j = 0; j < numCoveredPoints; ++j) {
249       if (coveredPoints[j] >= fStart && coveredPoints[j] < fEnd) {
250         numFaces++;
251         f = j;
252       }
253     }
254     PetscCheck(numFaces == 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT " vertices cannot define more than 1 facet (%" PetscInt_FMT ")", dim, numFaces);
255     PetscCall(DMLabelSetValue(bdLabelNew, coveredPoints[f], faceTagsNew[i]));
256     PetscCall(DMPlexRestoreJoin(*dmNew, dim, facePoints, &numCoveredPoints, &coveredPoints));
257   }
258   PetscCall(PetscFree4(facesNew, faceTagsNew, ridges, requiredFaces));
259 
260   /* Rebuild cell labels */
261   PetscCall(DMCreateLabel(*dmNew, rgLabel ? rgLabelName : rgName));
262   PetscCall(DMGetLabel(*dmNew, rgLabel ? rgLabelName : rgName, &rgLabelNew));
263   for (c = cStart; c < cEnd; ++c) PetscCall(DMLabelSetValue(rgLabelNew, c, cellTagsNew[c-cStart]));
264   PetscCall(PetscFree3(cellsNew, cellTagsNew, requiredCells));
265 
266   PetscFunctionReturn(0);
267 }
268