#include "../mmgcommon.h" /*I "petscdmplex.h" I*/ #include PetscBool ParMmgCite = PETSC_FALSE; const char ParMmgCitation[] = "@techreport{cirrottola:hal-02386837,\n" " title = {Parallel unstructured mesh adaptation using iterative remeshing and repartitioning},\n" " institution = {Inria Bordeaux},\n" " author = {L. Cirrottola and A. Froehly},\n" " number = {9307},\n" " note = {\\url{https://hal.inria.fr/hal-02386837}},\n" " year = {2019}\n}\n"; /* Coupling code for the ParMmg metric-based mesh adaptation package. */ PETSC_EXTERN PetscErrorCode DMAdaptMetric_ParMmg_Plex(DM dm, Vec vertexMetric, DMLabel bdLabel, DMLabel rgLabel, DM *dmNew) { MPI_Comm comm; const char *bdName = "_boundary_"; const char *rgName = "_regions_"; DM udm, cdm; DMLabel bdLabelNew, rgLabelNew; const char *bdLabelName, *rgLabelName; IS globalVertexNum; PetscSection coordSection; Vec coordinates; PetscSF sf; const PetscScalar *coords, *met; PetscReal *vertices, *metric, *verticesNew, *verticesNewLoc, gradationFactor, hausdorffNumber; PetscInt *cells, *cellsNew, *cellTags, *cellTagsNew, *verTags, *verTagsNew; PetscInt *bdFaces, *faceTags, *facesNew, *faceTagsNew; PetscInt *corners, *requiredCells, *requiredVer, *ridges, *requiredFaces; PetscInt cStart, cEnd, c, numCells, fStart, fEnd, f, numFaceTags, vStart, vEnd, v, numVertices; PetscInt numCellsNotShared, *cIsLeaf, numUsedVertices, *vertexNumber, *fIsIncluded; PetscInt dim, off, coff, maxConeSize, bdSize, i, j, k, Neq, verbosity, numIter; PetscInt *interfaces_lv, *interfaces_gv, *interfacesOffset; PetscMPIInt niranks, nrranks, numNgbRanks; PetscInt r, lv, gv; PetscInt *gv_new, *owners, *verticesNewSorted, pStart, pEnd; PetscInt numCellsNew, numVerticesNew, numCornersNew, numFacesNew, numVerticesNewLoc; const PetscInt *gV, *ioffset, *irootloc, *roffset, *rmine, *rremote; PetscBool flg = PETSC_FALSE, noInsert, noSwap, noMove, noSurf, isotropic, uniform; const PetscMPIInt *iranks, *rranks; PetscMPIInt numProcs, rank; PMMG_pParMesh parmesh = NULL; // DEVELOPER NOTE: ParMmg wants to know the rank of every process which is sharing a given point and // for this information to be conveyed to every process that is sharing that point. PetscFunctionBegin; PetscCall(PetscCitationsRegister(ParMmgCitation, &ParMmgCite)); PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); PetscCallMPI(MPI_Comm_size(comm, &numProcs)); PetscCallMPI(MPI_Comm_rank(comm, &rank)); if (bdLabel) { PetscCall(PetscObjectGetName((PetscObject)bdLabel, &bdLabelName)); PetscCall(PetscStrcmp(bdLabelName, bdName, &flg)); PetscCheck(!flg, comm, PETSC_ERR_ARG_WRONG, "\"%s\" cannot be used as label for boundary facets", bdLabelName); } if (rgLabel) { PetscCall(PetscObjectGetName((PetscObject)rgLabel, &rgLabelName)); PetscCall(PetscStrcmp(rgLabelName, rgName, &flg)); PetscCheck(!flg, comm, PETSC_ERR_ARG_WRONG, "\"%s\" cannot be used as label for element tags", rgLabelName); } /* Get mesh information */ PetscCall(DMGetDimension(dm, &dim)); PetscCheck(dim == 3, comm, PETSC_ERR_ARG_OUTOFRANGE, "ParMmg only works in 3D."); Neq = (dim * (dim + 1)) / 2; PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); PetscCall(DMPlexUninterpolate(dm, &udm)); PetscCall(DMPlexGetMaxSizes(udm, &maxConeSize, NULL)); numCells = cEnd - cStart; numVertices = vEnd - vStart; /* Get parallel data; work out which cells are owned and which are leaves */ PetscCall(PetscCalloc1(numCells, &cIsLeaf)); numCellsNotShared = numCells; niranks = nrranks = 0; if (numProcs > 1) { PetscCall(DMGetPointSF(dm, &sf)); PetscCall(PetscSFSetUp(sf)); PetscCall(PetscSFGetLeafRanks(sf, &niranks, &iranks, &ioffset, &irootloc)); PetscCall(PetscSFGetRootRanks(sf, &nrranks, &rranks, &roffset, &rmine, &rremote)); for (r = 0; r < nrranks; ++r) { for (i = roffset[r]; i < roffset[r + 1]; ++i) { if (rmine[i] >= cStart && rmine[i] < cEnd) { cIsLeaf[rmine[i] - cStart] = 1; numCellsNotShared--; } } } } /* Create a vertex numbering for ParMmg starting at 1. Vertices not included in any owned cell remain 0 and will be removed. Using this numbering, create cells. */ numUsedVertices = 0; PetscCall(PetscCalloc1(numVertices, &vertexNumber)); PetscCall(PetscMalloc1(numCellsNotShared * maxConeSize, &cells)); for (c = 0, coff = 0; c < numCells; ++c) { const PetscInt *cone; PetscInt coneSize, cl; if (!cIsLeaf[c]) { PetscCall(DMPlexGetConeSize(udm, cStart + c, &coneSize)); PetscCall(DMPlexGetCone(udm, cStart + c, &cone)); for (cl = 0; cl < coneSize; ++cl) { if (!vertexNumber[cone[cl] - vStart]) vertexNumber[cone[cl] - vStart] = ++numUsedVertices; cells[coff++] = vertexNumber[cone[cl] - vStart]; } } } /* Get array of vertex coordinates */ PetscCall(DMGetCoordinateDM(dm, &cdm)); PetscCall(DMGetLocalSection(cdm, &coordSection)); PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); PetscCall(VecGetArrayRead(coordinates, &coords)); PetscCall(PetscMalloc2(numUsedVertices * Neq, &metric, dim * numUsedVertices, &vertices)); for (v = 0; v < vEnd - vStart; ++v) { PetscCall(PetscSectionGetOffset(coordSection, v + vStart, &off)); if (vertexNumber[v]) { for (i = 0; i < dim; ++i) vertices[dim * (vertexNumber[v] - 1) + i] = PetscRealPart(coords[off + i]); } } PetscCall(VecRestoreArrayRead(coordinates, &coords)); /* Get face tags */ if (!bdLabel) { flg = PETSC_TRUE; PetscCall(DMLabelCreate(PETSC_COMM_SELF, bdName, &bdLabel)); PetscCall(DMPlexMarkBoundaryFaces(dm, 1, bdLabel)); } PetscCall(DMLabelGetBounds(bdLabel, &pStart, &pEnd)); PetscCall(PetscCalloc1(pEnd - pStart, &fIsIncluded)); for (f = pStart, bdSize = 0, numFaceTags = 0; f < pEnd; ++f) { PetscBool hasPoint; PetscInt *closure = NULL, closureSize, cl; PetscCall(DMLabelHasPoint(bdLabel, f, &hasPoint)); if ((!hasPoint) || (f < fStart) || (f >= fEnd)) continue; /* Only faces adjacent to an owned (non-leaf) cell are included */ PetscInt nnbrs; const PetscInt *nbrs; PetscCall(DMPlexGetSupportSize(dm, f, &nnbrs)); PetscCall(DMPlexGetSupport(dm, f, &nbrs)); for (c = 0; c < nnbrs; ++c) fIsIncluded[f - pStart] = fIsIncluded[f - pStart] || !cIsLeaf[nbrs[c]]; if (!fIsIncluded[f - pStart]) continue; numFaceTags++; PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure)); for (cl = 0; cl < closureSize * 2; cl += 2) { if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) ++bdSize; } PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure)); } PetscCall(PetscMalloc2(bdSize, &bdFaces, numFaceTags, &faceTags)); for (f = pStart, bdSize = 0, numFaceTags = 0; f < pEnd; ++f) { PetscInt *closure = NULL, closureSize, cl; if (!fIsIncluded[f - pStart]) continue; PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure)); for (cl = 0; cl < closureSize * 2; cl += 2) { if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) bdFaces[bdSize++] = vertexNumber[closure[cl] - vStart]; } PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure)); PetscCall(DMLabelGetValue(bdLabel, f, &faceTags[numFaceTags++])); } PetscCall(PetscFree(fIsIncluded)); /* Get cell tags */ PetscCall(PetscCalloc2(numUsedVertices, &verTags, numCellsNotShared, &cellTags)); if (rgLabel) { for (c = cStart, coff = 0; c < cEnd; ++c) { if (!cIsLeaf[c - cStart]) PetscCall(DMLabelGetValue(rgLabel, c, &cellTags[coff++])); } } PetscCall(PetscFree(cIsLeaf)); /* Get metric, using only the upper triangular part */ PetscCall(VecViewFromOptions(vertexMetric, NULL, "-adapt_metric_view")); PetscCall(VecGetArrayRead(vertexMetric, &met)); PetscCall(DMPlexMetricIsIsotropic(dm, &isotropic)); PetscCall(DMPlexMetricIsUniform(dm, &uniform)); for (v = 0; v < (vEnd - vStart); ++v) { PetscInt vv = vertexNumber[v]; if (!vv--) continue; for (i = 0, k = 0; i < dim; ++i) { for (j = i; j < dim; ++j, ++k) { if (isotropic) { if (i == j) { if (uniform) metric[Neq * vv + k] = PetscRealPart(met[0]); else metric[Neq * vv + k] = PetscRealPart(met[v]); } else metric[Neq * vv + k] = 0.0; } else metric[Neq * vv + k] = PetscRealPart(met[dim * dim * v + dim * i + j]); } } } PetscCall(VecRestoreArrayRead(vertexMetric, &met)); /* Build ParMmg communicators: the list of vertices between two partitions */ numNgbRanks = 0; if (numProcs > 1) { DM rankdm; PetscSection rankSection, rankGlobalSection; PetscSF rankSF; const PetscInt *degree; PetscInt *rankOfUsedVertices, *rankOfUsedMultiRootLeaves, *usedCopies; PetscInt *rankArray, *rankGlobalArray, *interfacesPerRank; PetscInt offset, mrl, rootDegreeCnt, s, shareCnt, gv; PetscCall(PetscSFComputeDegreeBegin(sf, °ree)); PetscCall(PetscSFComputeDegreeEnd(sf, °ree)); PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); for (i = 0, rootDegreeCnt = 0; i < pEnd - pStart; ++i) rootDegreeCnt += degree[i]; /* rankOfUsedVertices, point-array: rank+1 if vertex and in use */ PetscCall(PetscCalloc1(pEnd - pStart, &rankOfUsedVertices)); for (i = 0; i < pEnd - pStart; ++i) rankOfUsedVertices[i] = -1; for (i = vStart; i < vEnd; ++i) { if (vertexNumber[i - vStart]) rankOfUsedVertices[i] = rank; } /* rankOfUsedMultiRootLeaves, multiroot-array: rank if vertex and in use, else -1 */ PetscCall(PetscMalloc1(rootDegreeCnt, &rankOfUsedMultiRootLeaves)); PetscCall(PetscSFGatherBegin(sf, MPIU_INT, rankOfUsedVertices, rankOfUsedMultiRootLeaves)); PetscCall(PetscSFGatherEnd(sf, MPIU_INT, rankOfUsedVertices, rankOfUsedMultiRootLeaves)); PetscCall(PetscFree(rankOfUsedVertices)); /* usedCopies, point-array: if vertex, shared by how many processes */ PetscCall(PetscCalloc1(pEnd - pStart, &usedCopies)); for (i = 0, mrl = 0; i < vStart - pStart; i++) mrl += degree[i]; for (i = vStart - pStart; i < vEnd - pStart; ++i) { for (j = 0; j < degree[i]; j++, mrl++) { if (rankOfUsedMultiRootLeaves[mrl] != -1) usedCopies[i]++; } if (vertexNumber[i - vStart + pStart]) usedCopies[i]++; } PetscCall(PetscSFBcastBegin(sf, MPIU_INT, usedCopies, usedCopies, MPI_REPLACE)); PetscCall(PetscSFBcastEnd(sf, MPIU_INT, usedCopies, usedCopies, MPI_REPLACE)); /* Create a section to store ranks of vertices shared by more than one process */ PetscCall(PetscSectionCreate(comm, &rankSection)); PetscCall(PetscSectionSetNumFields(rankSection, 1)); PetscCall(PetscSectionSetChart(rankSection, pStart, pEnd)); for (i = vStart - pStart; i < vEnd - pStart; ++i) { if (usedCopies[i] > 1) PetscCall(PetscSectionSetDof(rankSection, i + pStart, usedCopies[i])); } PetscCall(PetscSectionSetUp(rankSection)); PetscCall(PetscSectionCreateGlobalSection(rankSection, sf, PETSC_FALSE, PETSC_FALSE, PETSC_TRUE, &rankGlobalSection)); PetscCall(PetscSectionGetStorageSize(rankGlobalSection, &s)); PetscCall(PetscMalloc1(s, &rankGlobalArray)); for (i = 0, mrl = 0; i < vStart - pStart; i++) mrl += degree[i]; for (i = vStart - pStart, k = 0; i < vEnd - pStart; ++i) { if (usedCopies[i] > 1 && degree[i]) { PetscCall(PetscSectionGetOffset(rankSection, k, &offset)); if (vertexNumber[i - vStart + pStart]) rankGlobalArray[k++] = rank; for (j = 0; j < degree[i]; j++, mrl++) { if (rankOfUsedMultiRootLeaves[mrl] != -1) rankGlobalArray[k++] = rankOfUsedMultiRootLeaves[mrl]; } } else mrl += degree[i]; } PetscCall(PetscFree(rankOfUsedMultiRootLeaves)); PetscCall(PetscFree(usedCopies)); PetscCall(PetscSectionDestroy(&rankGlobalSection)); /* Broadcast the array of ranks. (We want all processes to know all the ranks that are looking at each point. Above, we tell the roots. Here, the roots tell the leaves.) */ PetscCall(DMClone(dm, &rankdm)); PetscCall(DMSetLocalSection(rankdm, rankSection)); PetscCall(DMGetSectionSF(rankdm, &rankSF)); PetscCall(PetscSectionGetStorageSize(rankSection, &s)); PetscCall(PetscMalloc1(s, &rankArray)); PetscCall(PetscSFBcastBegin(rankSF, MPI_INT, rankGlobalArray, rankArray, MPI_REPLACE)); PetscCall(PetscSFBcastEnd(rankSF, MPI_INT, rankGlobalArray, rankArray, MPI_REPLACE)); PetscCall(PetscFree(rankGlobalArray)); PetscCall(DMDestroy(&rankdm)); /* Count the number of interfaces per rank, not including those on the root */ PetscCall(PetscCalloc1(numProcs, &interfacesPerRank)); for (v = vStart; v < vEnd; v++) { if (vertexNumber[v - vStart]) { PetscCall(PetscSectionGetDof(rankSection, v, &shareCnt)); if (shareCnt) { PetscCall(PetscSectionGetOffset(rankSection, v, &offset)); for (j = 0; j < shareCnt; j++) interfacesPerRank[rankArray[offset + j]]++; } } } for (r = 0, k = 0, interfacesPerRank[rank] = 0; r < numProcs; r++) k += interfacesPerRank[r]; /* Get the degree of the vertex */ PetscCall(PetscMalloc3(k, &interfaces_lv, k, &interfaces_gv, numProcs + 1, &interfacesOffset)); interfacesOffset[0] = 0; for (r = 0; r < numProcs; r++) { interfacesOffset[r + 1] = interfacesOffset[r] + interfacesPerRank[r]; if (interfacesPerRank[r]) numNgbRanks++; interfacesPerRank[r] = 0; } /* Get the local and global vertex numbers at interfaces */ PetscCall(DMPlexGetVertexNumbering(dm, &globalVertexNum)); PetscCall(ISGetIndices(globalVertexNum, &gV)); for (v = vStart; v < vEnd; v++) { if (vertexNumber[v - vStart]) { PetscCall(PetscSectionGetDof(rankSection, v, &shareCnt)); if (shareCnt) { PetscCall(PetscSectionGetOffset(rankSection, v, &offset)); for (j = 0; j < shareCnt; j++) { r = rankArray[offset + j]; if (r == rank) continue; k = interfacesOffset[r] + interfacesPerRank[r]++; interfaces_lv[k] = vertexNumber[v - vStart]; gv = gV[v - vStart]; interfaces_gv[k] = gv < 0 ? -gv : gv + 1; } } } } PetscCall(PetscFree(interfacesPerRank)); PetscCall(PetscFree(rankArray)); PetscCall(ISRestoreIndices(globalVertexNum, &gV)); PetscCall(PetscSectionDestroy(&rankSection)); } PetscCall(DMDestroy(&udm)); PetscCall(PetscFree(vertexNumber)); /* Send the data to ParMmg and remesh */ PetscCall(DMPlexMetricNoInsertion(dm, &noInsert)); PetscCall(DMPlexMetricNoSwapping(dm, &noSwap)); PetscCall(DMPlexMetricNoMovement(dm, &noMove)); PetscCall(DMPlexMetricNoSurf(dm, &noSurf)); PetscCall(DMPlexMetricGetVerbosity(dm, &verbosity)); PetscCall(DMPlexMetricGetNumIterations(dm, &numIter)); PetscCall(DMPlexMetricGetGradationFactor(dm, &gradationFactor)); PetscCall(DMPlexMetricGetHausdorffNumber(dm, &hausdorffNumber)); PetscCallMMG_NONSTANDARD(PMMG_Init_parMesh, PMMG_ARG_start, PMMG_ARG_ppParMesh, &parmesh, PMMG_ARG_pMesh, PMMG_ARG_pMet, PMMG_ARG_dim, 3, PMMG_ARG_MPIComm, comm, PMMG_ARG_end); PetscCallMMG_NONSTANDARD(PMMG_Set_meshSize, parmesh, numUsedVertices, numCellsNotShared, 0, numFaceTags, 0, 0); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_APImode, PMMG_APIDISTRIB_nodes); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_noinsert, noInsert); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_noswap, noSwap); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_nomove, noMove); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_nosurf, noSurf); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_verbose, verbosity); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_globalNum, 1); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_niter, numIter); PetscCallMMG_NONSTANDARD(PMMG_Set_dparameter, parmesh, PMMG_DPARAM_hgrad, gradationFactor); PetscCallMMG_NONSTANDARD(PMMG_Set_dparameter, parmesh, PMMG_DPARAM_hausd, hausdorffNumber); PetscCallMMG_NONSTANDARD(PMMG_Set_vertices, parmesh, vertices, verTags); PetscCallMMG_NONSTANDARD(PMMG_Set_tetrahedra, parmesh, cells, cellTags); PetscCallMMG_NONSTANDARD(PMMG_Set_triangles, parmesh, bdFaces, faceTags); PetscCallMMG_NONSTANDARD(PMMG_Set_metSize, parmesh, MMG5_Vertex, numUsedVertices, MMG5_Tensor); PetscCallMMG_NONSTANDARD(PMMG_Set_tensorMets, parmesh, metric); PetscCallMMG_NONSTANDARD(PMMG_Set_numberOfNodeCommunicators, parmesh, numNgbRanks); for (r = 0, c = 0; r < numProcs; ++r) { if (interfacesOffset[r + 1] > interfacesOffset[r]) { PetscCallMMG_NONSTANDARD(PMMG_Set_ithNodeCommunicatorSize, parmesh, c, r, interfacesOffset[r + 1] - interfacesOffset[r]); PetscCallMMG_NONSTANDARD(PMMG_Set_ithNodeCommunicator_nodes, parmesh, c++, &interfaces_lv[interfacesOffset[r]], &interfaces_gv[interfacesOffset[r]], 1); } } PetscCallMMG(PMMG_parmmglib_distributed, parmesh); PetscCall(PetscFree(cells)); PetscCall(PetscFree2(metric, vertices)); PetscCall(PetscFree2(bdFaces, faceTags)); PetscCall(PetscFree2(verTags, cellTags)); if (numProcs > 1) PetscCall(PetscFree3(interfaces_lv, interfaces_gv, interfacesOffset)); /* Retrieve mesh from Mmg */ numCornersNew = 4; PetscCallMMG_NONSTANDARD(PMMG_Get_meshSize, parmesh, &numVerticesNew, &numCellsNew, 0, &numFacesNew, 0, 0); PetscCall(PetscMalloc4(dim * numVerticesNew, &verticesNew, numVerticesNew, &verTagsNew, numVerticesNew, &corners, numVerticesNew, &requiredVer)); PetscCall(PetscMalloc3((dim + 1) * numCellsNew, &cellsNew, numCellsNew, &cellTagsNew, numCellsNew, &requiredCells)); PetscCall(PetscMalloc4(dim * numFacesNew, &facesNew, numFacesNew, &faceTagsNew, numFacesNew, &ridges, numFacesNew, &requiredFaces)); PetscCallMMG_NONSTANDARD(PMMG_Get_vertices, parmesh, verticesNew, verTagsNew, corners, requiredVer); PetscCallMMG_NONSTANDARD(PMMG_Get_tetrahedra, parmesh, cellsNew, cellTagsNew, requiredCells); PetscCallMMG_NONSTANDARD(PMMG_Get_triangles, parmesh, facesNew, faceTagsNew, requiredFaces); PetscCall(PetscMalloc2(numVerticesNew, &owners, numVerticesNew, &gv_new)); PetscCallMMG_NONSTANDARD(PMMG_Set_iparameter, parmesh, PMMG_IPARAM_globalNum, 1); PetscCallMMG_NONSTANDARD(PMMG_Get_verticesGloNum, parmesh, gv_new, owners); for (i = 0; i < dim * numFacesNew; ++i) facesNew[i] -= 1; for (i = 0; i < (dim + 1) * numCellsNew; ++i) cellsNew[i] = gv_new[cellsNew[i] - 1] - 1; for (i = 0, numVerticesNewLoc = 0; i < numVerticesNew; ++i) { if (owners[i] == rank) numVerticesNewLoc++; } PetscCall(PetscMalloc1(numVerticesNewLoc * dim, &verticesNewLoc)); for (i = 0, c = 0; i < numVerticesNew; i++) { if (owners[i] == rank) { for (j = 0; j < dim; ++j) verticesNewLoc[dim * c + j] = verticesNew[dim * i + j]; c++; } } /* Reorder for consistency with DMPlex */ for (i = 0; i < numCellsNew; ++i) PetscCall(DMPlexInvertCell(DM_POLYTOPE_TETRAHEDRON, &cellsNew[4 * i])); /* Create new plex */ PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, dim, numCellsNew, numVerticesNewLoc, PETSC_DECIDE, numCornersNew, PETSC_TRUE, cellsNew, dim, verticesNewLoc, NULL, &verticesNewSorted, dmNew)); PetscCallMMG_NONSTANDARD(PMMG_Free_all, PMMG_ARG_start, PMMG_ARG_ppParMesh, &parmesh, PMMG_ARG_end); PetscCall(PetscFree4(verticesNew, verTagsNew, corners, requiredVer)); /* Get adapted mesh information */ PetscCall(DMPlexGetHeightStratum(*dmNew, 0, &cStart, &cEnd)); PetscCall(DMPlexGetHeightStratum(*dmNew, 1, &fStart, &fEnd)); PetscCall(DMPlexGetDepthStratum(*dmNew, 0, &vStart, &vEnd)); /* Rebuild boundary label */ PetscCall(DMCreateLabel(*dmNew, flg ? bdName : bdLabelName)); PetscCall(DMGetLabel(*dmNew, flg ? bdName : bdLabelName, &bdLabelNew)); for (i = 0; i < numFacesNew; i++) { PetscBool hasTag = PETSC_FALSE; PetscInt numCoveredPoints, numFaces = 0, facePoints[3]; const PetscInt *coveredPoints = NULL; for (j = 0; j < dim; ++j) { lv = facesNew[i * dim + j]; gv = gv_new[lv] - 1; PetscCall(PetscFindInt(gv, numVerticesNew, verticesNewSorted, &lv)); facePoints[j] = lv + vStart; } PetscCall(DMPlexGetFullJoin(*dmNew, dim, facePoints, &numCoveredPoints, &coveredPoints)); for (j = 0; j < numCoveredPoints; ++j) { if (coveredPoints[j] >= fStart && coveredPoints[j] < fEnd) { numFaces++; f = j; } } PetscCheck(numFaces == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "%" PetscInt_FMT " vertices cannot define more than 1 facet (%" PetscInt_FMT ")", dim, numFaces); PetscCall(DMLabelHasStratum(bdLabel, faceTagsNew[i], &hasTag)); if (hasTag) PetscCall(DMLabelSetValue(bdLabelNew, coveredPoints[f], faceTagsNew[i])); PetscCall(DMPlexRestoreJoin(*dmNew, dim, facePoints, &numCoveredPoints, &coveredPoints)); } PetscCall(PetscFree4(facesNew, faceTagsNew, ridges, requiredFaces)); PetscCall(PetscFree2(owners, gv_new)); PetscCall(PetscFree(verticesNewLoc)); if (flg) PetscCall(DMLabelDestroy(&bdLabel)); /* Rebuild cell labels */ PetscCall(DMCreateLabel(*dmNew, rgLabel ? rgLabelName : rgName)); PetscCall(DMGetLabel(*dmNew, rgLabel ? rgLabelName : rgName, &rgLabelNew)); for (c = cStart; c < cEnd; ++c) PetscCall(DMLabelSetValue(rgLabelNew, c, cellTagsNew[c - cStart])); PetscCall(PetscFree3(cellsNew, cellTagsNew, requiredCells)); PetscFunctionReturn(PETSC_SUCCESS); }