xref: /petsc/src/dm/impls/plex/plexadapt.c (revision 0f7e110dd4f5716a1a6e45be10edbffe00300112)
10bbe5d31Sbarral #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
20bbe5d31Sbarral #ifdef PETSC_HAVE_PRAGMATIC
30bbe5d31Sbarral #include <pragmatic/cpragmatic.h>
40bbe5d31Sbarral #endif
50bbe5d31Sbarral 
60bbe5d31Sbarral 
70bbe5d31Sbarral 
80bbe5d31Sbarral #undef __FUNCT__
952b40ca0Sbarral #define __FUNCT__ "DMPlexAdapt"
10*0f7e110dSbarral /*@
11*0f7e110dSbarral   DMPlexAdapt - Generates a mesh adapted to the specified metric field using the pragmatic library.
12*0f7e110dSbarral 
13*0f7e110dSbarral   Input Parameters:
14*0f7e110dSbarral + dm - The DM object
15*0f7e110dSbarral . metric - The metric to which the mesh is adapted, defined vertex-wise.
16*0f7e110dSbarral - bdyLabelName - Label name for boundary tags. These will be preserved in the output mesh. bdyLabelName should be different from "boundary".
17*0f7e110dSbarral 
18*0f7e110dSbarral   Output Parameter:
19*0f7e110dSbarral . dmAdapted  - Pointer to the DM object containing the adapted mesh
20*0f7e110dSbarral 
21*0f7e110dSbarral   Level: advanced
22*0f7e110dSbarral 
23*0f7e110dSbarral .seealso: DMCoarsen(), DMRefine()
24*0f7e110dSbarral @*/
256b1afcafSbarral PetscErrorCode DMPlexAdapt(DM dm, Vec metric, const char bdyLabelName[], DM *dmAdapted)
260bbe5d31Sbarral {
270bbe5d31Sbarral #ifdef PETSC_HAVE_PRAGMATIC
280bbe5d31Sbarral   DM                   udm, coordDM;
296b1afcafSbarral   DMLabel              bd, bdTags, bdTagsAdp;
300bbe5d31Sbarral   Vec                  coordinates;
310bbe5d31Sbarral   PetscSection         coordSection;
320bbe5d31Sbarral   IS                   bdIS;
33*0f7e110dSbarral   double              *coordsAdp;
34*0f7e110dSbarral   const PetscScalar   *coords;
356b1afcafSbarral   PetscReal           *x, *y, *z, *xAdp, *yAdp, *zAdp;
36*0f7e110dSbarral   const PetscScalar   *metricArray;
37*0f7e110dSbarral   PetscReal           *met;
380bbe5d31Sbarral   const PetscInt      *faces;
396b1afcafSbarral   PetscInt            *cells, *cellsAdp, *bdFaces, *bdFaceIds;
40*0f7e110dSbarral   PetscInt            *boundaryTags;
416b1afcafSbarral   PetscInt             dim, numCornersAdp, cStart, cEnd, numCells, numCellsAdp, c;
426b1afcafSbarral   PetscInt             vStart, vEnd, numVertices, numVerticesAdp, v;
436b1afcafSbarral   PetscInt             numBdFaces, f, maxConeSize, bdSize, coff;
44*0f7e110dSbarral   PetscInt            *cell, iVer, cellOff, i, j, idx, facet;
45*0f7e110dSbarral   PetscInt             perm[4], isInFacetClosure[4]; // 4 = max number of facets for an element in 2D & 3D. Only for simplicial meshes
462499d69cSbarral   PetscBool            flag, hasBdyFacet;
470bbe5d31Sbarral #endif
480bbe5d31Sbarral   PetscErrorCode       ierr;
490bbe5d31Sbarral   MPI_Comm             comm;
500bbe5d31Sbarral 
510bbe5d31Sbarral   PetscFunctionBegin;
520bbe5d31Sbarral   ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr);
530bbe5d31Sbarral #ifdef PETSC_HAVE_PRAGMATIC
540bbe5d31Sbarral   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
550bbe5d31Sbarral   ierr = DMGetCoordinateDM(dm, &coordDM);CHKERRQ(ierr);
560bbe5d31Sbarral   ierr = DMGetDefaultSection(coordDM, &coordSection);CHKERRQ(ierr);
570bbe5d31Sbarral   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
580bbe5d31Sbarral   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
590bbe5d31Sbarral   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
600bbe5d31Sbarral   ierr = DMPlexUninterpolate(dm, &udm);CHKERRQ(ierr);
610bbe5d31Sbarral   ierr = DMPlexGetMaxSizes(udm, &maxConeSize, NULL);CHKERRQ(ierr);
620bbe5d31Sbarral   numCells    = cEnd - cStart;
630bbe5d31Sbarral   numVertices = vEnd - vStart;
640bbe5d31Sbarral   ierr = PetscCalloc5(numVertices, &x, numVertices, &y, numVertices, &z, numCells*maxConeSize, &cells, dim*dim*numVertices, &met);CHKERRQ(ierr);
650bbe5d31Sbarral   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
660bbe5d31Sbarral   ierr = VecGetArrayRead(metric, &metricArray);CHKERRQ(ierr);
670bbe5d31Sbarral   for (v = vStart; v < vEnd; ++v) {
680bbe5d31Sbarral     PetscInt off;
690bbe5d31Sbarral 
700bbe5d31Sbarral     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
710bbe5d31Sbarral     x[v-vStart] = coords[off+0];
720bbe5d31Sbarral     y[v-vStart] = coords[off+1];
730bbe5d31Sbarral     if (dim > 2) z[v-vStart] = coords[off+2];
740bbe5d31Sbarral     ierr = PetscMemcpy(&met[dim*dim*(v-vStart)], &metricArray[dim*off], dim*dim*sizeof(PetscScalar));CHKERRQ(ierr);
750bbe5d31Sbarral   }
760bbe5d31Sbarral   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
770bbe5d31Sbarral   ierr = VecRestoreArrayRead(metric, &metricArray);CHKERRQ(ierr);
780bbe5d31Sbarral   for (c = 0, coff = 0; c < numCells; ++c) {
790bbe5d31Sbarral     const PetscInt *cone;
800bbe5d31Sbarral     PetscInt        coneSize, cl;
810bbe5d31Sbarral 
820bbe5d31Sbarral     ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr);
830bbe5d31Sbarral     ierr = DMPlexGetCone(udm, c, &cone);CHKERRQ(ierr);
840bbe5d31Sbarral     for (cl = 0; cl < coneSize; ++cl) cells[coff++] = cone[cl] - vStart;
850bbe5d31Sbarral   }
860bbe5d31Sbarral   switch (dim) {
870bbe5d31Sbarral   case 2:
880bbe5d31Sbarral     pragmatic_2d_init(&numVertices, &numCells, cells, x, y);
890bbe5d31Sbarral     break;
900bbe5d31Sbarral   case 3:
910bbe5d31Sbarral     pragmatic_3d_init(&numVertices, &numCells, cells, x, y, z);
920bbe5d31Sbarral     break;
930bbe5d31Sbarral   default:
940bbe5d31Sbarral     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No Pragmatic adaptation defined for dimension %d", dim);
950bbe5d31Sbarral   }
960bbe5d31Sbarral   /* Create boundary mesh */
974190e864Sbarral   if (bdyLabelName) {
986b1afcafSbarral     ierr = PetscStrcmp(bdyLabelName, "boundary", &flag);CHKERRQ(ierr);
996b1afcafSbarral     if (flag) {
1006b1afcafSbarral       SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "\"%s\" cannot be used as label for boundary facets", bdyLabelName);
1014190e864Sbarral     }
1026b1afcafSbarral     ierr = DMGetLabel(dm, bdyLabelName, &bdTags);CHKERRQ(ierr);
1036b1afcafSbarral   }
104*0f7e110dSbarral   /* TODO To avoid marking bdy facets again if bdyLabelName exists, could/should we loop over bdyLabelName stratas ? */
1050bbe5d31Sbarral   ierr = DMLabelCreate("boundary", &bd);CHKERRQ(ierr);
1060bbe5d31Sbarral   ierr = DMPlexMarkBoundaryFaces(dm, bd);CHKERRQ(ierr);
1070bbe5d31Sbarral   ierr = DMLabelGetStratumIS(bd, 1, &bdIS);CHKERRQ(ierr);
1080bbe5d31Sbarral   ierr = DMLabelGetStratumSize(bd, 1, &numBdFaces);CHKERRQ(ierr);
1090bbe5d31Sbarral   ierr = ISGetIndices(bdIS, &faces);CHKERRQ(ierr);
1106b1afcafSbarral   /* TODO why not assume that we are considering simplicial meshes, in which case bdSize = dim*numBdFaces ? */
1110bbe5d31Sbarral   for (f = 0, bdSize = 0; f < numBdFaces; ++f) {
1120bbe5d31Sbarral     PetscInt *closure = NULL;
1130bbe5d31Sbarral     PetscInt  closureSize, cl;
1140bbe5d31Sbarral 
1150bbe5d31Sbarral     ierr = DMPlexGetTransitiveClosure(dm, faces[f], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1160bbe5d31Sbarral     for (cl = 0; cl < closureSize*2; cl += 2) {
1170bbe5d31Sbarral       if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) ++bdSize;
1180bbe5d31Sbarral     }
1190bbe5d31Sbarral     ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1200bbe5d31Sbarral   }
1210bbe5d31Sbarral   ierr = PetscMalloc2(bdSize, &bdFaces, numBdFaces, &bdFaceIds);CHKERRQ(ierr);
1220bbe5d31Sbarral   for (f = 0, bdSize = 0; f < numBdFaces; ++f) {
1230bbe5d31Sbarral     PetscInt *closure = NULL;
1240bbe5d31Sbarral     PetscInt  closureSize, cl;
1250bbe5d31Sbarral 
1260bbe5d31Sbarral     ierr = DMPlexGetTransitiveClosure(dm, faces[f], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1270bbe5d31Sbarral     for (cl = 0; cl < closureSize*2; cl += 2) {
1280bbe5d31Sbarral       if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) bdFaces[bdSize++] = closure[cl] - vStart;
1290bbe5d31Sbarral     }
1306b1afcafSbarral     if (bdyLabelName) {
1316b1afcafSbarral       ierr = DMLabelGetValue(bdTags, faces[f], &bdFaceIds[f]);CHKERRQ(ierr);
1326b1afcafSbarral     } else {
1330bbe5d31Sbarral       bdFaceIds[f] = 1;
1346b1afcafSbarral     }
1350bbe5d31Sbarral     ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1360bbe5d31Sbarral   }
1370bbe5d31Sbarral   ierr = ISDestroy(&bdIS);CHKERRQ(ierr);
1380bbe5d31Sbarral   ierr = DMLabelDestroy(&bd);CHKERRQ(ierr);
1390bbe5d31Sbarral   pragmatic_set_boundary(&numBdFaces, bdFaces, bdFaceIds);
1400bbe5d31Sbarral   pragmatic_set_metric(met);
1410bbe5d31Sbarral   pragmatic_adapt();
1426b1afcafSbarral   ierr = PetscFree5(x, y, z, cells, met);CHKERRQ(ierr);
1436b1afcafSbarral   ierr = PetscFree2(bdFaces, bdFaceIds);CHKERRQ(ierr);
1446b1afcafSbarral   ierr = PetscFree(coords);CHKERRQ(ierr);
1450bbe5d31Sbarral   /* Read out mesh */
1466b1afcafSbarral   pragmatic_get_info(&numVerticesAdp, &numCellsAdp);
1476b1afcafSbarral   ierr = PetscMalloc1(numVerticesAdp*dim, &coordsAdp);CHKERRQ(ierr);
1480bbe5d31Sbarral   switch (dim) {
1490bbe5d31Sbarral   case 2:
1506b1afcafSbarral     ierr = PetscMalloc2(numVerticesAdp, &xAdp, numVerticesAdp, &yAdp);CHKERRQ(ierr);
1516b1afcafSbarral     zAdp = NULL;
1526b1afcafSbarral     pragmatic_get_coords_2d(xAdp, yAdp);
1536b1afcafSbarral     numCornersAdp = 3;
1546b1afcafSbarral     for (v = 0; v < numVerticesAdp; ++v) {coordsAdp[v*2+0] = xAdp[v]; coordsAdp[v*2+1] = yAdp[v];}
1550bbe5d31Sbarral     break;
1560bbe5d31Sbarral   case 3:
1576b1afcafSbarral     ierr = PetscMalloc3(numVerticesAdp, &xAdp, numVerticesAdp, &yAdp, numVerticesAdp, &zAdp);CHKERRQ(ierr);
1586b1afcafSbarral     pragmatic_get_coords_3d(xAdp, yAdp, zAdp);
1596b1afcafSbarral     numCornersAdp = 4;
1606b1afcafSbarral     for (v = 0; v < numVerticesAdp; ++v) {coordsAdp[v*3+0] = xAdp[v]; coordsAdp[v*3+1] = yAdp[v]; coordsAdp[v*3+2] = zAdp[v];}
1610bbe5d31Sbarral     break;
1620bbe5d31Sbarral   default:
1636b1afcafSbarral     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No Pragmatic adaptation defined for dimension %d", dim);
1640bbe5d31Sbarral   }
1656b1afcafSbarral   ierr = PetscMalloc1(numCellsAdp*(dim+1), &cellsAdp);CHKERRQ(ierr); // only for simplicial meshes
1666b1afcafSbarral   pragmatic_get_elements(cellsAdp);
1676b1afcafSbarral   ierr = DMPlexCreate(comm, dmAdapted);CHKERRQ(ierr);
1686b1afcafSbarral   ierr = DMPlexCreateFromCellList(PetscObjectComm((PetscObject) dm), dim, numCellsAdp, numVerticesAdp, numCornersAdp, PETSC_TRUE, cellsAdp, dim, coordsAdp, dmAdapted);CHKERRQ(ierr);
169f7caa48eSbarral   /* Read out boundary tags */
170f7caa48eSbarral   pragmatic_get_boundaryTags(&boundaryTags);
171f7caa48eSbarral   if (!bdyLabelName) bdyLabelName = "boundary";
1726b1afcafSbarral   ierr = DMCreateLabel(*dmAdapted, bdyLabelName);CHKERRQ(ierr);
1736b1afcafSbarral   ierr = DMGetLabel(*dmAdapted, bdyLabelName, &bdTagsAdp);CHKERRQ(ierr);
1746b1afcafSbarral   ierr = DMPlexGetHeightStratum(*dmAdapted, 0, &cStart, &cEnd);CHKERRQ(ierr);
1756b1afcafSbarral   ierr = DMPlexGetDepthStratum(*dmAdapted, 0, &vStart, &vEnd);CHKERRQ(ierr);
176f7caa48eSbarral   for (c = cStart; c < cEnd; ++c) {
177f7caa48eSbarral     PetscInt       *cellClosure = NULL;
178f7caa48eSbarral     PetscInt        cellClosureSize, cl;
179f7caa48eSbarral     PetscInt       *facetClosure = NULL;
180f7caa48eSbarral     PetscInt        facetClosureSize, cl2;
181f7caa48eSbarral     const PetscInt *facetList;
182f7caa48eSbarral     PetscInt        facetListSize, f;
183f7caa48eSbarral 
184*0f7e110dSbarral     cellOff = (c-cStart)*(dim+1);  // gives the offset corresponding to the cell in pragmatic boundary arrays. Only for simplicial meshes
1852499d69cSbarral     hasBdyFacet = 0;
186*0f7e110dSbarral     for (i = 0; i < dim+1; ++i) {   // only for simplicial meshes
1872499d69cSbarral       if (boundaryTags[cellOff+i]) {
1882499d69cSbarral         hasBdyFacet = 1;
1892499d69cSbarral         break;
1902499d69cSbarral       }
1912499d69cSbarral     }
192*0f7e110dSbarral     if (!hasBdyFacet) continue; // The cell has no boundary edge/facet => no boundary tagging
1932499d69cSbarral 
194*0f7e110dSbarral     cell = &cellsAdp[cellOff]; // pointing to the current cell in the cellsAdp table
1956b1afcafSbarral     ierr = DMPlexGetTransitiveClosure(*dmAdapted, c, PETSC_TRUE, &cellClosureSize, &cellClosure);CHKERRQ(ierr);
1966b1afcafSbarral     /* first, encode the permutation of the vertices indices betwenn the cell closure and pragmatic ordering */
197fc167ce7Sbarral     j = 0;
198f7caa48eSbarral     for (cl = 0; cl < cellClosureSize*2; cl += 2) {
199f7caa48eSbarral       if ((cellClosure[cl] < vStart) || (cellClosure[cl] >= vEnd)) continue;
200f7caa48eSbarral       iVer = cellClosure[cl] - vStart;
201*0f7e110dSbarral       for (i = 0; i < dim+1; ++i) {  // only for simplicial meshes
202f7caa48eSbarral         if (iVer == cell[i]) {
203fc167ce7Sbarral           perm[j] = i;    // the cl-th element of the closure is the i-th vertex of the cell
204f7caa48eSbarral           break;
205f7caa48eSbarral         }
206f7caa48eSbarral       }
207fc167ce7Sbarral       j++;
208f7caa48eSbarral     }
2096b1afcafSbarral     ierr = DMPlexGetCone(*dmAdapted, c, &facetList);CHKERRQ(ierr);     // list of edges/facets of the cell
2106b1afcafSbarral     ierr = DMPlexGetConeSize(*dmAdapted, c, &facetListSize);CHKERRQ(ierr);
211*0f7e110dSbarral     /* then, for each edge/facet of the cell, find the opposite vertex (ie the one in the closure of the cell and not in the closure of the facet/edge) */
212f7caa48eSbarral     for (f = 0; f < facetListSize; ++f){
213f7caa48eSbarral       facet = facetList[f];
2146b1afcafSbarral       ierr = DMPlexGetTransitiveClosure(*dmAdapted, facet, PETSC_TRUE, &facetClosureSize, &facetClosure);CHKERRQ(ierr);
2156b1afcafSbarral       /* loop over the vertices of the cell closure, and check if each vertex belongs to the edge/facet closure */
216*0f7e110dSbarral       /* TODO should we use bitmaps to mark vertices instead of a static array ? */
217f7caa48eSbarral       PetscMemzero(isInFacetClosure, sizeof(isInFacetClosure));
218fc167ce7Sbarral       j = 0;
219f7caa48eSbarral       for (cl = 0; cl < cellClosureSize*2; cl += 2) {
220*0f7e110dSbarral         if ((cellClosure[cl] < vStart) || (cellClosure[cl] >= vEnd)) continue;
221f7caa48eSbarral         for (cl2 = 0; cl2 < facetClosureSize*2; cl2 += 2){
222f7caa48eSbarral           if ((facetClosure[cl2] < vStart) || (facetClosure[cl2] >= vEnd)) continue;
223f7caa48eSbarral           if (cellClosure[cl] == facetClosure[cl2]) {
224fc167ce7Sbarral             isInFacetClosure[j] = 1;
225f7caa48eSbarral           }
226f7caa48eSbarral         }
227fc167ce7Sbarral         j++;
228f7caa48eSbarral       }
2296b1afcafSbarral       /* the vertex that was not marked is the vertex opposite to the edge/facet, ie the one giving the edge/facet boundary tag in pragmatic */
230fc167ce7Sbarral       j = 0;
231f7caa48eSbarral       for (cl = 0; cl < cellClosureSize*2; cl += 2) {
232fc167ce7Sbarral         if ((cellClosure[cl] < vStart) || (cellClosure[cl] >= vEnd)) continue;
233fc167ce7Sbarral         if (!isInFacetClosure[j]) {
234fc167ce7Sbarral           idx = cellOff + perm[j];
2356b1afcafSbarral           if (boundaryTags[idx]) {
2366b1afcafSbarral             ierr = DMLabelSetValue(bdTagsAdp, facet, boundaryTags[idx]);CHKERRQ(ierr);
2376b1afcafSbarral           }
238f7caa48eSbarral           break;
239f7caa48eSbarral         }
240fc167ce7Sbarral         j++;
241f7caa48eSbarral       }
2426b1afcafSbarral       ierr = DMPlexRestoreTransitiveClosure(*dmAdapted, facet, PETSC_TRUE, &facetClosureSize, &facetClosure);CHKERRQ(ierr);
243f7caa48eSbarral     }
2446b1afcafSbarral     ierr = DMPlexRestoreTransitiveClosure(*dmAdapted, c, PETSC_TRUE, &cellClosureSize, &cellClosure);CHKERRQ(ierr);
245f7caa48eSbarral   }
2460bbe5d31Sbarral   pragmatic_finalize();
2476b1afcafSbarral   ierr = PetscFree5(xAdp, yAdp, zAdp, cellsAdp, coordsAdp);CHKERRQ(ierr);
2480bbe5d31Sbarral #endif
2490bbe5d31Sbarral   PetscFunctionReturn(0);
2500bbe5d31Sbarral }
251