PetscErrorCode CheckMesh(DM dm, AppCtx *user) { PetscReal detJ, J[9], refVol = 1.0; PetscReal vol; PetscInt dim, depth, d, cStart, cEnd, c; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); for (d = 0; d < dim; ++d) { refVol *= 2.0; } ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); for (c = cStart; c < cEnd; ++c) { ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr); if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, |J| = %g", c, detJ); if (user->debug) {PetscPrintf(PETSC_COMM_SELF, "FEM Volume: %g\n", detJ*refVol);CHKERRQ(ierr);} if (depth > 1) { ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr); if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, vol); if (user->debug) {PetscPrintf(PETSC_COMM_SELF, "FVM Volume: %g\n", vol);CHKERRQ(ierr);} } } PetscFunctionReturn(0); }
/*@C DMPlexInterpolate - Take in a cell-vertex mesh and return one with all intermediate faces, edges, etc. Collective on DM Input Parameters: + dm - The DMPlex object with only cells and vertices - dmInt - If NULL a new DM is created, otherwise the interpolated DM is put into the given DM Output Parameter: . dmInt - The complete DMPlex object Level: intermediate .keywords: mesh .seealso: DMPlexUninterpolate(), DMPlexCreateFromCellList() @*/ PetscErrorCode DMPlexInterpolate(DM dm, DM *dmInt) { DM idm, odm = dm; PetscSF sfPoint; PetscInt depth, dim, d; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscLogEventBegin(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr); ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); if (dim <= 1) { ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); idm = dm; } for (d = 1; d < dim; ++d) { /* Create interpolated mesh */ if ((d == dim-1) && *dmInt) {idm = *dmInt;} else {ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);} ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr); ierr = DMSetDimension(idm, dim);CHKERRQ(ierr); if (depth > 0) { ierr = DMPlexInterpolateFaces_Internal(odm, 1, idm);CHKERRQ(ierr); ierr = DMGetPointSF(odm, &sfPoint);CHKERRQ(ierr); ierr = DMPlexInterpolatePointSF(idm, sfPoint, depth);CHKERRQ(ierr); } if (odm != dm) {ierr = DMDestroy(&odm);CHKERRQ(ierr);} odm = idm; } *dmInt = idm; ierr = PetscLogEventEnd(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode SetupFE(DM dm, PetscInt Nc, PetscBool simplex, const char name[], PetscErrorCode (*setup)(DM, AppCtx *), void *ctx) { AppCtx *user = (AppCtx *) ctx; DM cdm = dm; PetscFE fe; char prefix[PETSC_MAX_PATH_LEN]; PetscInt dim; PetscErrorCode ierr; PetscFunctionBegin; /* Create finite element */ ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = PetscSNPrintf(prefix, PETSC_MAX_PATH_LEN, "%s_", name);CHKERRQ(ierr); ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) dm), dim, Nc, simplex, name ? prefix : NULL, -1, &fe);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) fe, name);CHKERRQ(ierr); /* Set discretization and boundary conditions for each mesh */ ierr = DMSetField(dm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); ierr = DMCreateDS(dm);CHKERRQ(ierr); ierr = (*setup)(dm, user);CHKERRQ(ierr); while (cdm) { ierr = DMCopyDisc(dm, cdm);CHKERRQ(ierr); if (user->useNearNullspace) {ierr = DMSetNearNullSpaceConstructor(cdm, 0, CreateElasticityNullSpace);CHKERRQ(ierr);} /* TODO: Check whether the boundary of coarse meshes is marked */ ierr = DMGetCoarseDM(cdm, &cdm);CHKERRQ(ierr); } ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); PetscFunctionReturn(0); }
PETSC_EXTERN void PETSC_STDCALL dmdagetneighbors_(DM *da,PetscMPIInt *ranks,PetscErrorCode *ierr) { const PetscMPIInt *r; PetscInt n,dim; *ierr = DMDAGetNeighbors(*da,&r);if (*ierr) return; *ierr = DMGetDimension(*da,&dim);if (*ierr) return; if (dim == 2) n = 9; else n = 27; *ierr = PetscMemcpy(ranks,r,n*sizeof(PetscMPIInt)); }
PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) { PetscInt *tmpClosure,*tmpAdj,*visits; PetscInt c,cStart,cEnd,pStart,pEnd; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)); ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); npoints = pEnd - pStart; ierr = PetscMalloc3(maxClosureSize,&tmpClosure,npoints,&lvisits,npoints,&visits);CHKERRQ(ierr); ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr); ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); for (c=cStart; c<cEnd; c++) { PetscInt *support = tmpClosure; ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr); for (p=0; p<supportSize; p++) lvisits[support[p]]++; } ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFReduceEnd (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr); ierr = PetscSFBcastEnd (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr); ierr = PetscSFGetRanks();CHKERRQ(ierr); ierr = PetscMalloc2(maxClosureSize*maxClosureSize,&cellmat,npoints,&owner);CHKERRQ(ierr); for (c=cStart; c<cEnd; c++) { ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr); /* Depth-first walk of transitive closure. At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat. This contribution is added to dnz if owning ranks of p and q match, to onz otherwise. */ } ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFReduceEnd (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode CreateBoundaryMesh(DM dm, DMLabel *bdLabel, DM *subdm, AppCtx *user) { DMLabel label; PetscInt dim; PetscErrorCode ierr; PetscFunctionBeginUser; ierr = DMLabelCreate(PETSC_COMM_SELF, "sub", &label);CHKERRQ(ierr); ierr = DMPlexMarkBoundaryFaces(dm, 1, label);CHKERRQ(ierr); ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr); ierr = DMPlexCreateSubmesh(dm, label, 1, PETSC_TRUE, subdm);CHKERRQ(ierr); ierr = DMGetDimension(*subdm, &dim);CHKERRQ(ierr); ierr = SetupDiscretization(*subdm, dim, user->cellSimplex, user);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) *subdm, "boundary");CHKERRQ(ierr); ierr = DMViewFromOptions(*subdm, NULL, "-sub_dm_view");CHKERRQ(ierr); if (bdLabel) *bdLabel = label; else ierr = DMLabelDestroy(&label);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) { PetscInt dim = user->dim; PetscBool cellSimplex = user->cellSimplex; const char *filename = user->filename; size_t len; PetscMPIInt rank; PetscErrorCode ierr; PetscFunctionBegin; ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = PetscStrlen(filename, &len);CHKERRQ(ierr); if (len) { ierr = DMPlexCreateFromFile(comm, filename, PETSC_FALSE, dm);CHKERRQ(ierr); ierr = DMGetDimension(*dm, &dim);CHKERRQ(ierr); } else { PetscReal L[3] = {1.0, 1.0, 1.0}; PetscReal maxCell[3]; PetscInt d; for (d = 0; d < dim; ++d) {maxCell[d] = (1.0/user->faces[d])*1.1;} ierr = DMPlexCreateBoxMesh(comm, dim, cellSimplex, user->faces, NULL, NULL, user->periodicity, PETSC_TRUE, dm);CHKERRQ(ierr); ierr = DMSetPeriodicity(*dm, user->isPeriodic, maxCell, L, user->periodicity);CHKERRQ(ierr); } { DM pdm = NULL; PetscPartitioner part; ierr = DMPlexGetPartitioner(*dm, &part);CHKERRQ(ierr); ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr); /* Distribute mesh over processes */ ierr = DMPlexDistribute(*dm, 0, NULL, &pdm);CHKERRQ(ierr); if (pdm) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = pdm; } } ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) *dm, "Mesh");CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); user->dm = *dm; PetscFunctionReturn(0); }
static PetscErrorCode CreateAuxiliaryData(DM dm, DM *auxdm, Vec *la, AppCtx *user) { PetscErrorCode (**afuncs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *); PetscInt dim, Nf, f; PetscErrorCode ierr; PetscFunctionBeginUser; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); ierr = PetscMalloc1(Nf, &afuncs);CHKERRQ(ierr); for (f = 0; f < Nf; ++f) afuncs[f] = linear; ierr = DMClone(dm, auxdm);CHKERRQ(ierr); ierr = SetupDiscretization(*auxdm, dim, user->cellSimplex, user);CHKERRQ(ierr); ierr = DMCreateLocalVector(*auxdm, la);CHKERRQ(ierr); ierr = DMProjectFunctionLocal(dm, 0.0, afuncs, NULL, INSERT_VALUES, *la);CHKERRQ(ierr); ierr = VecViewFromOptions(*la, NULL, "-local_aux_view");CHKERRQ(ierr); ierr = PetscFree(afuncs);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@C DMDAGetElements - Gets an array containing the indices (in local coordinates) of all the local elements Not Collective Input Parameter: . dm - the DM object Output Parameters: + nel - number of local elements . nen - number of element nodes - e - the local indices of the elements' vertices Level: intermediate Notes: Call DMDARestoreElements() once you have finished accessing the elements. Each process uniquely owns a subset of the elements. That is no element is owned by two or more processes. If on each process you integrate over its owned elements and use ADD_VALUES in Vec/MatSetValuesLocal() then you'll obtain the correct result. .seealso: DMDAElementType, DMDASetElementType(), VecSetValuesLocal(), MatSetValuesLocal(), DMGlobalToLocalBegin(), DMLocalToGlobalBegin() @*/ PetscErrorCode DMDAGetElements(DM dm,PetscInt *nel,PetscInt *nen,const PetscInt *e[]) { PetscInt dim; PetscErrorCode ierr; DM_DA *dd = (DM_DA*)dm->data; PetscFunctionBegin; if (dd->stencil_type == DMDA_STENCIL_STAR) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DMDAGetElement() requires you use a stencil type of DMDA_STENCIL_BOX"); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); if (dim==-1) { *nel = 0; *nen = 0; *e = NULL; } else if (dim==1) { ierr = DMDAGetElements_1D(dm,nel,nen,e);CHKERRQ(ierr); } else if (dim==2) { ierr = DMDAGetElements_2D(dm,nel,nen,e);CHKERRQ(ierr); } else if (dim==3) { ierr = DMDAGetElements_3D(dm,nel,nen,e);CHKERRQ(ierr); } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"DMDA dimension not 1, 2, or 3, it is %D\n",dim); PetscFunctionReturn(0); }
static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *options, DM *dm) { PetscInt dim = options->dim; PetscInt *faces = options->faces; PetscBool simplex = options->simplex; PetscBool interpolate = options->interpolate; const char *filename = options->filename; size_t len; PetscMPIInt rank; PetscErrorCode ierr; PetscFunctionBegin; ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = PetscStrlen(filename, &len);CHKERRQ(ierr); if (len) { ierr = DMPlexCreateFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr); ierr = DMGetDimension(*dm, &options->dim);CHKERRQ(ierr); } else { ierr = DMPlexCreateBoxMesh(comm, dim, simplex, faces, NULL, NULL, NULL, interpolate, dm);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/*@C DMPlexGenerate - Generates a mesh. Not Collective Input Parameters: + boundary - The DMPlex boundary object . name - The mesh generation package name - interpolate - Flag to create intermediate mesh elements Output Parameter: . mesh - The DMPlex object Level: intermediate .keywords: mesh, elements .seealso: DMPlexCreate(), DMRefine() @*/ PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh) { PetscInt dim; char genname[1024]; PetscBool flg; PetscErrorCode ierr; PetscFunctionList fl; PetscFunctionBegin; PetscValidHeaderSpecific(boundary, DM_CLASSID, 1); PetscValidLogicalCollectiveBool(boundary, interpolate, 2); ierr = DMGetDimension(boundary, &dim);CHKERRQ(ierr); ierr = PetscOptionsGetString(((PetscObject) boundary)->options,((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr); if (flg) name = genname; fl = DMPlexGenerateList; if (name) { while (fl) { ierr = PetscStrcmp(fl->name,name,&flg);CHKERRQ(ierr); if (flg) { ierr = (*fl->generate)(boundary,interpolate,mesh);CHKERRQ(ierr); PetscFunctionReturn(0); } fl = fl->next; } SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Grid generator %g not registered",name); } else { while (fl) { if (boundary->dim == fl->dim) { ierr = (*fl->generate)(boundary,interpolate,mesh);CHKERRQ(ierr); PetscFunctionReturn(0); } fl = fl->next; } SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"No grid generator of dimension %D registered",boundary->dim); } PetscFunctionReturn(0); }
static PetscErrorCode TestLocalDofOrder(DM dm, AppCtx *ctx) { PetscFE fe[3]; PetscSection s; PetscInt dim, Nf, f; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) dm), dim, dim, ctx->simplex, "field0_", -1, &fe[0]);CHKERRQ(ierr); ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) dm), dim, 1, ctx->simplex, "field1_", -1, &fe[1]);CHKERRQ(ierr); ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) dm), dim, 1, ctx->simplex, "field2_", -1, &fe[2]);CHKERRQ(ierr); ierr = DMSetField(dm, 0, NULL, (PetscObject) fe[0]);CHKERRQ(ierr); ierr = DMSetField(dm, 1, NULL, (PetscObject) fe[1]);CHKERRQ(ierr); ierr = DMSetField(dm, 2, NULL, (PetscObject) fe[2]);CHKERRQ(ierr); ierr = DMCreateDS(dm);CHKERRQ(ierr); ierr = DMGetSection(dm, &s);CHKERRQ(ierr); ierr = PetscObjectViewFromOptions((PetscObject) s, NULL, "-dof_view");CHKERRQ(ierr); ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&fe[f]);CHKERRQ(ierr);} PetscFunctionReturn(0); }
/* This interpolates faces for cells at some stratum */ static PetscErrorCode DMPlexInterpolateFaces_Internal(DM dm, PetscInt cellDepth, DM idm) { DMLabel subpointMap; PetscHashIJKL faceTable; PetscInt *pStart, *pEnd; PetscInt cellDim, depth, faceDepth = cellDepth, numPoints = 0, faceSizeAll = 0, face, c, d; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDimension(dm, &cellDim);CHKERRQ(ierr); /* HACK: I need a better way to determine face dimension, or an alternative to GetFaces() */ ierr = DMPlexGetSubpointMap(dm, &subpointMap);CHKERRQ(ierr); if (subpointMap) ++cellDim; ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); ++depth; ++cellDepth; cellDim -= depth - cellDepth; ierr = PetscMalloc2(depth+1,&pStart,depth+1,&pEnd);CHKERRQ(ierr); for (d = depth-1; d >= faceDepth; --d) { ierr = DMPlexGetDepthStratum(dm, d, &pStart[d+1], &pEnd[d+1]);CHKERRQ(ierr); } ierr = DMPlexGetDepthStratum(dm, -1, NULL, &pStart[faceDepth]);CHKERRQ(ierr); pEnd[faceDepth] = pStart[faceDepth]; for (d = faceDepth-1; d >= 0; --d) { ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr); } if (pEnd[cellDepth] > pStart[cellDepth]) {ierr = DMPlexGetFaces_Internal(dm, cellDim, pStart[cellDepth], NULL, &faceSizeAll, NULL);CHKERRQ(ierr);} if (faceSizeAll > 4) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll); ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr); for (c = pStart[cellDepth], face = pStart[faceDepth]; c < pEnd[cellDepth]; ++c) { const PetscInt *cellFaces; PetscInt numCellFaces, faceSize, cf; ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr); if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll); for (cf = 0; cf < numCellFaces; ++cf) { const PetscInt *cellFace = &cellFaces[cf*faceSize]; PetscHashIJKLKey key; PetscHashIJKLIter missing, iter; if (faceSize == 2) { key.i = PetscMin(cellFace[0], cellFace[1]); key.j = PetscMax(cellFace[0], cellFace[1]); key.k = 0; key.l = 0; } else { key.i = cellFace[0]; key.j = cellFace[1]; key.k = cellFace[2]; key.l = faceSize > 3 ? cellFace[3] : 0; ierr = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr); } ierr = PetscHashIJKLPut(faceTable, key, &missing, &iter);CHKERRQ(ierr); if (missing) {ierr = PetscHashIJKLSet(faceTable, iter, face++);CHKERRQ(ierr);} } ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr); } pEnd[faceDepth] = face; ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr); /* Count new points */ for (d = 0; d <= depth; ++d) { numPoints += pEnd[d]-pStart[d]; } ierr = DMPlexSetChart(idm, 0, numPoints);CHKERRQ(ierr); /* Set cone sizes */ for (d = 0; d <= depth; ++d) { PetscInt coneSize, p; if (d == faceDepth) { for (p = pStart[d]; p < pEnd[d]; ++p) { /* I see no way to do this if we admit faces of different shapes */ ierr = DMPlexSetConeSize(idm, p, faceSizeAll);CHKERRQ(ierr); } } else if (d == cellDepth) { for (p = pStart[d]; p < pEnd[d]; ++p) { /* Number of cell faces may be different from number of cell vertices*/ ierr = DMPlexGetFaces_Internal(dm, cellDim, p, &coneSize, NULL, NULL);CHKERRQ(ierr); ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr); } } else { for (p = pStart[d]; p < pEnd[d]; ++p) { ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr); } } } ierr = DMSetUp(idm);CHKERRQ(ierr); /* Get face cones from subsets of cell vertices */ if (faceSizeAll > 4) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll); ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr); for (d = depth; d > cellDepth; --d) { const PetscInt *cone; PetscInt p; for (p = pStart[d]; p < pEnd[d]; ++p) { ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); ierr = DMPlexSetCone(idm, p, cone);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm, p, &cone);CHKERRQ(ierr); ierr = DMPlexSetConeOrientation(idm, p, cone);CHKERRQ(ierr); } } for (c = pStart[cellDepth], face = pStart[faceDepth]; c < pEnd[cellDepth]; ++c) { const PetscInt *cellFaces; PetscInt numCellFaces, faceSize, cf; ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr); if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll); for (cf = 0; cf < numCellFaces; ++cf) { const PetscInt *cellFace = &cellFaces[cf*faceSize]; PetscHashIJKLKey key; PetscHashIJKLIter missing, iter; if (faceSize == 2) { key.i = PetscMin(cellFace[0], cellFace[1]); key.j = PetscMax(cellFace[0], cellFace[1]); key.k = 0; key.l = 0; } else { key.i = cellFace[0]; key.j = cellFace[1]; key.k = cellFace[2]; key.l = faceSize > 3 ? cellFace[3] : 0; ierr = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr); } ierr = PetscHashIJKLPut(faceTable, key, &missing, &iter);CHKERRQ(ierr); if (missing) { ierr = DMPlexSetCone(idm, face, cellFace);CHKERRQ(ierr); ierr = PetscHashIJKLSet(faceTable, iter, face);CHKERRQ(ierr); ierr = DMPlexInsertCone(idm, c, cf, face++);CHKERRQ(ierr); } else { const PetscInt *cone; PetscInt coneSize, ornt, i, j, f; ierr = PetscHashIJKLGet(faceTable, iter, &f);CHKERRQ(ierr); ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr); /* Orient face: Do not allow reverse orientation at the first vertex */ ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr); ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr); if (coneSize != faceSize) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %D for face %D should be %D", coneSize, f, faceSize); /* - First find the initial vertex */ for (i = 0; i < faceSize; ++i) if (cellFace[0] == cone[i]) break; /* - Try forward comparison */ for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+j)%faceSize]) break; if (j == faceSize) { if ((faceSize == 2) && (i == 1)) ornt = -2; else ornt = i; } else { /* - Try backward comparison */ for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+faceSize-j)%faceSize]) break; if (j == faceSize) { if (i == 0) ornt = -faceSize; else ornt = -i; } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not determine face orientation"); } ierr = DMPlexInsertConeOrientation(idm, c, cf, ornt);CHKERRQ(ierr); } } ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr); } if (face != pEnd[faceDepth]) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-pStart[faceDepth], pEnd[faceDepth]-pStart[faceDepth]); ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr); ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr); ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr); ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr); ierr = DMPlexStratify(idm);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) { MPI_Comm comm; MatType mtype; PetscSF sf, sfDof, sfAdj; PetscSection leafSectionAdj, rootSectionAdj, sectionAdj, anchorSectionAdj; PetscInt nroots, nleaves, l, p; const PetscInt *leaves; const PetscSFNode *remotes; PetscInt dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols; PetscInt *tmpAdj = NULL, *adj, *rootAdj, *anchorAdj = NULL, *cols, *remoteOffsets; PetscInt adjSize; PetscLayout rLayout; PetscInt locRows, rStart, rEnd, r; PetscMPIInt size; PetscBool doCommLocal, doComm, debug = PETSC_FALSE, isSymBlock, isSymSeqBlock, isSymMPIBlock; PetscBool useAnchors; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3); PetscValidHeaderSpecific(sectionGlobal, PETSC_SECTION_CLASSID, 4); PetscValidHeaderSpecific(A, MAT_CLASSID, 9); if (dnz) PetscValidPointer(dnz,5); if (onz) PetscValidPointer(onz,6); if (dnzu) PetscValidPointer(dnzu,7); if (onzu) PetscValidPointer(onzu,8); ierr = PetscLogEventBegin(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); doCommLocal = (size > 1) && (nroots >= 0) ? PETSC_TRUE : PETSC_FALSE; ierr = MPI_Allreduce(&doCommLocal, &doComm, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr); /* Create dof SF based on point SF */ if (debug) { ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sf, NULL);CHKERRQ(ierr); } ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr); } /* Create section for dof adjacency (dof ==> # adj dof) */ ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr); /* Fill in the ghost dofs on the interface */ ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr); /* use constraints in finding adjacency in this routine */ ierr = DMPlexGetAdjacencyUseAnchors(dm,&useAnchors);CHKERRQ(ierr); ierr = DMPlexSetAdjacencyUseAnchors(dm,PETSC_TRUE);CHKERRQ(ierr); /* section - maps points to (# dofs, local dofs) sectionGlobal - maps points to (# dofs, global dofs) leafSectionAdj - maps unowned local dofs to # adj dofs rootSectionAdj - maps owned local dofs to # adj dofs adj - adj global dofs indexed by leafSectionAdj rootAdj - adj global dofs indexed by rootSectionAdj sf - describes shared points across procs sfDof - describes shared dofs across procs sfAdj - describes shared adjacent dofs across procs ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point. (0). If there are point-to-point constraints, add the adjacencies of constrained points to anchors in anchorAdj (This is done in DMPlexComputeAnchorAdjacencies()) 1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj Reduce those counts to rootSectionAdj (now redundantly counting some interface points) 2. Visit owned points on interface, count adjacencies placing in rootSectionAdj Create sfAdj connecting rootSectionAdj and leafSectionAdj 3. Visit unowned points on interface, write adjacencies to adj Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies) 4. Visit owned points on interface, write adjacencies to rootAdj Remove redundancy in rootAdj ** The last two traversals use transitive closure 5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj) Allocate memory addressed by sectionAdj (cols) 6. Visit all owned points in the subdomain, insert dof adjacencies into cols ** Knowing all the column adjacencies, check ownership and sum into dnz and onz */ ierr = DMPlexComputeAnchorAdjacencies(dm,section,sectionGlobal,&anchorSectionAdj,&anchorAdj);CHKERRQ(ierr); for (l = 0; l < nleaves; ++l) { PetscInt dof, off, d, q, anDof; PetscInt p = leaves[l], numAdj = PETSC_DETERMINE; if ((p < pStart) || (p >= pEnd)) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(leafSectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr); ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */ if (doComm) { ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); } if (debug) { ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Add in local adjacency sizes for owned dofs on interface (roots) */ for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(rootSectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Create adj SF based on dof SF */ ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr); } ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr); /* Create leaf adjacency */ ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr); ierr = PetscCalloc1(adjSize, &adj);CHKERRQ(ierr); for (l = 0; l < nleaves; ++l) { PetscInt dof, off, d, q, anDof, anOff; PetscInt p = leaves[l], numAdj = PETSC_DETERMINE; if ((p < pStart) || (p >= pEnd)) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { PetscInt aoff, i = 0; ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd) { adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd; ++i; } } for (q = 0; q < anDof; q++) { adj[aoff+i] = anchorAdj[anOff+q]; ++i; } } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Gather adjacenct indices to root */ ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr); ierr = PetscMalloc1(adjSize, &rootAdj);CHKERRQ(ierr); for (r = 0; r < adjSize; ++r) rootAdj[r] = -1; if (doComm) { ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr); ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr); } ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr); ierr = PetscFree(adj);CHKERRQ(ierr); /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Add in local adjacency indices for owned dofs on interface (roots) */ for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof, anOff; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { PetscInt adof, aoff, i; ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); i = adof-1; for (q = 0; q < anDof; q++) { rootAdj[aoff+i] = anchorAdj[anOff+q]; --i; } for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd) { rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; --i; } } } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Compress indices */ ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, cdof, off, d; PetscInt adof, aoff; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; for (d = off; d < off+dof-cdof; ++d) { ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr); ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr); } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Build adjacency section: Maps global indices to sets of adjacent global indices */ ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, §ionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof; PetscBool found = PETSC_TRUE; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); for (d = 0; d < dof-cdof; ++d) { PetscInt ldof, rdof; ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); if (ldof > 0) { /* We do not own this point */ } else if (rdof > 0) { ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr); } else { found = PETSC_FALSE; } } if (found) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, noff; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr); for (d = goff; d < goff+dof-cdof; ++d) { ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = goff; d < goff+dof-cdof; ++d) { ierr = PetscSectionAddDof(sectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Get adjacent indices */ ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr); ierr = PetscMalloc1(numCols, &cols);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof, anOff; PetscBool found = PETSC_TRUE; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); for (d = 0; d < dof-cdof; ++d) { PetscInt ldof, rdof; ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); if (ldof > 0) { /* We do not own this point */ } else if (rdof > 0) { PetscInt aoff, roff; ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr); ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr); } else { found = PETSC_FALSE; } } if (found) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = goff; d < goff+dof-cdof; ++d) { PetscInt adof, aoff, i = 0; ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; const PetscInt *ncind; /* Adjacent points may not be in the section chart */ if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd, ++i) { cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; } } for (q = 0; q < anDof; q++, i++) { cols[aoff+i] = anchorAdj[anOff + q]; } if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p); } } ierr = PetscSectionDestroy(&anchorSectionAdj);CHKERRQ(ierr); ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr); ierr = PetscFree(anchorAdj);CHKERRQ(ierr); ierr = PetscFree(rootAdj);CHKERRQ(ierr); ierr = PetscFree(tmpAdj);CHKERRQ(ierr); /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Create allocation vectors from adjacency graph */ ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr); ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr); ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); /* Only loop over blocks of rows */ if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs); for (r = rStart/bs; r < rEnd/bs; ++r) { const PetscInt row = r*bs; PetscInt numCols, cStart, c; ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr); for (c = cStart; c < cStart+numCols; ++c) { if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) { ++dnz[r-rStart]; if (cols[c] >= row) ++dnzu[r-rStart]; } else { ++onz[r-rStart]; if (cols[c] >= row) ++onzu[r-rStart]; } } } if (bs > 1) { for (r = 0; r < locRows/bs; ++r) { dnz[r] /= bs; onz[r] /= bs; dnzu[r] /= bs; onzu[r] /= bs; } } /* Set matrix pattern */ ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr); ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); /* Check for symmetric storage */ ierr = MatGetType(A, &mtype);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); if (isSymBlock || isSymSeqBlock || isSymMPIBlock) {ierr = MatSetOption(A, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);} /* Fill matrix with zeros */ if (fillMatrix) { PetscScalar *values; PetscInt maxRowLen = 0; for (r = rStart; r < rEnd; ++r) { PetscInt len; ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr); maxRowLen = PetscMax(maxRowLen, len); } ierr = PetscCalloc1(maxRowLen, &values);CHKERRQ(ierr); for (r = rStart; r < rEnd; ++r) { PetscInt numCols, cStart; ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr); ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr); } ierr = PetscFree(values);CHKERRQ(ierr); ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); } /* restore original useAnchors */ ierr = DMPlexSetAdjacencyUseAnchors(dm,useAnchors);CHKERRQ(ierr); ierr = PetscSectionDestroy(§ionAdj);CHKERRQ(ierr); ierr = PetscFree(cols);CHKERRQ(ierr); ierr = PetscLogEventEnd(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ DMPlexOrient - Give a consistent orientation to the input mesh Input Parameters: . dm - The DM Note: The orientation data for the DM are change in-place. $ This routine will fail for non-orientable surfaces, such as the Moebius strip. Level: advanced .seealso: DMCreate(), DMPLEX @*/ PetscErrorCode DMPlexOrient(DM dm) { MPI_Comm comm; PetscSF sf; const PetscInt *lpoints; const PetscSFNode *rpoints; PetscSFNode *rorntComp = NULL, *lorntComp = NULL; PetscInt *numNeighbors, **neighbors; PetscSFNode *nrankComp; PetscBool *match, *flipped; PetscBT seenCells, flippedCells, seenFaces; PetscInt *faceFIFO, fTop, fBottom, *cellComp, *faceComp; PetscInt numLeaves, numRoots, dim, h, cStart, cEnd, c, cell, fStart, fEnd, face, off, totNeighbors = 0; PetscMPIInt rank, size, numComponents, comp = 0; PetscBool flg, flg2; PetscViewer viewer = NULL, selfviewer = NULL; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); ierr = PetscOptionsHasName(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-orientation_view", &flg);CHKERRQ(ierr); ierr = PetscOptionsHasName(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-orientation_view_synchronized", &flg2);CHKERRQ(ierr); ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints);CHKERRQ(ierr); /* Truth Table mismatch flips do action mismatch flipA ^ flipB action F 0 flips no F F F F 1 flip yes F T T F 2 flips no T F T T 0 flips yes T T F T 1 flip no T 2 flips yes */ ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr); ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr); ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr); ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr); ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr); ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr); ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr); ierr = PetscCalloc3(fEnd - fStart, &faceFIFO, cEnd-cStart, &cellComp, fEnd-fStart, &faceComp);CHKERRQ(ierr); /* OLD STYLE - Add an integer array over cells and faces (component) for connected component number Foreach component - Mark the initial cell as seen - Process component as usual - Set component for all seenCells - Wipe seenCells and seenFaces (flippedCells can stay) - Generate parallel adjacency for component using SF and seenFaces - Collect numComponents adj data from each proc to 0 - Build same serial graph - Use same solver - Use Scatterv to to send back flipped flags for each component - Negate flippedCells by component NEW STYLE - Create the adj on each process - Bootstrap to complete graph on proc 0 */ /* Loop over components */ for (cell = cStart; cell < cEnd; ++cell) cellComp[cell-cStart] = -1; do { /* Look for first unmarked cell */ for (cell = cStart; cell < cEnd; ++cell) if (cellComp[cell-cStart] < 0) break; if (cell >= cEnd) break; /* Initialize FIFO with first cell in component */ { const PetscInt *cone; PetscInt coneSize; fTop = fBottom = 0; ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr); ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr); for (c = 0; c < coneSize; ++c) { faceFIFO[fBottom++] = cone[c]; ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr); } ierr = PetscBTSet(seenCells, cell-cStart);CHKERRQ(ierr); } /* Consider each face in FIFO */ while (fTop < fBottom) { ierr = DMPlexCheckFace_Internal(dm, faceFIFO, &fTop, &fBottom, cStart, fStart, fEnd, seenCells, flippedCells, seenFaces);CHKERRQ(ierr); } /* Set component for cells and faces */ for (cell = 0; cell < cEnd-cStart; ++cell) { if (PetscBTLookup(seenCells, cell)) cellComp[cell] = comp; } for (face = 0; face < fEnd-fStart; ++face) { if (PetscBTLookup(seenFaces, face)) faceComp[face] = comp; } /* Wipe seenCells and seenFaces for next component */ ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr); ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr); ++comp; } while (1); numComponents = comp; if (flg) { PetscViewer v; ierr = PetscViewerASCIIGetStdout(comm, &v);CHKERRQ(ierr); ierr = PetscViewerASCIIPushSynchronized(v);CHKERRQ(ierr); ierr = PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for serial flipped cells:\n", rank);CHKERRQ(ierr); ierr = PetscBTView(cEnd-cStart, flippedCells, v);CHKERRQ(ierr); ierr = PetscViewerFlush(v);CHKERRQ(ierr); ierr = PetscViewerASCIIPopSynchronized(v);CHKERRQ(ierr); } /* Now all subdomains are oriented, but we need a consistent parallel orientation */ if (numLeaves >= 0) { /* Store orientations of boundary faces*/ ierr = PetscCalloc2(numRoots,&rorntComp,numRoots,&lorntComp);CHKERRQ(ierr); for (face = fStart; face < fEnd; ++face) { const PetscInt *cone, *support, *ornt; PetscInt coneSize, supportSize; ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); if (supportSize != 1) continue; ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr); ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm, support[0], &ornt);CHKERRQ(ierr); for (c = 0; c < coneSize; ++c) if (cone[c] == face) break; if (dim == 1) { /* Use cone position instead, shifted to -1 or 1 */ if (PetscBTLookup(flippedCells, support[0]-cStart)) rorntComp[face].rank = 1-c*2; else rorntComp[face].rank = c*2-1; } else { if (PetscBTLookup(flippedCells, support[0]-cStart)) rorntComp[face].rank = ornt[c] < 0 ? -1 : 1; else rorntComp[face].rank = ornt[c] < 0 ? 1 : -1; } rorntComp[face].index = faceComp[face-fStart]; } /* Communicate boundary edge orientations */ ierr = PetscSFBcastBegin(sf, MPIU_2INT, rorntComp, lorntComp);CHKERRQ(ierr); ierr = PetscSFBcastEnd(sf, MPIU_2INT, rorntComp, lorntComp);CHKERRQ(ierr); } /* Get process adjacency */ ierr = PetscMalloc2(numComponents, &numNeighbors, numComponents, &neighbors);CHKERRQ(ierr); viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm)); if (flg2) {ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);} ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&selfviewer);CHKERRQ(ierr); for (comp = 0; comp < numComponents; ++comp) { PetscInt l, n; numNeighbors[comp] = 0; ierr = PetscMalloc1(PetscMax(numLeaves, 0), &neighbors[comp]);CHKERRQ(ierr); /* I know this is p^2 time in general, but for bounded degree its alright */ for (l = 0; l < numLeaves; ++l) { const PetscInt face = lpoints[l]; /* Find a representative face (edge) separating pairs of procs */ if ((face >= fStart) && (face < fEnd) && (faceComp[face-fStart] == comp)) { const PetscInt rrank = rpoints[l].rank; const PetscInt rcomp = lorntComp[face].index; for (n = 0; n < numNeighbors[comp]; ++n) if ((rrank == rpoints[neighbors[comp][n]].rank) && (rcomp == lorntComp[lpoints[neighbors[comp][n]]].index)) break; if (n >= numNeighbors[comp]) { PetscInt supportSize; ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); if (supportSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %d", supportSize); if (flg) {ierr = PetscViewerASCIIPrintf(selfviewer, "[%d]: component %d, Found representative leaf %d (face %d) connecting to face %d on (%d, %d) with orientation %d\n", rank, comp, l, face, rpoints[l].index, rrank, rcomp, lorntComp[face].rank);CHKERRQ(ierr);} neighbors[comp][numNeighbors[comp]++] = l; } } } totNeighbors += numNeighbors[comp]; } ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&selfviewer);CHKERRQ(ierr); ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); if (flg2) {ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);} ierr = PetscMalloc2(totNeighbors, &nrankComp, totNeighbors, &match);CHKERRQ(ierr); for (comp = 0, off = 0; comp < numComponents; ++comp) { PetscInt n; for (n = 0; n < numNeighbors[comp]; ++n, ++off) { const PetscInt face = lpoints[neighbors[comp][n]]; const PetscInt o = rorntComp[face].rank*lorntComp[face].rank; if (o < 0) match[off] = PETSC_TRUE; else if (o > 0) match[off] = PETSC_FALSE; else SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid face %d (%d, %d) neighbor: %d comp: %d", face, rorntComp[face], lorntComp[face], neighbors[comp][n], comp); nrankComp[off].rank = rpoints[neighbors[comp][n]].rank; nrankComp[off].index = lorntComp[lpoints[neighbors[comp][n]]].index; } ierr = PetscFree(neighbors[comp]);CHKERRQ(ierr); } /* Collect the graph on 0 */ if (numLeaves >= 0) { Mat G; PetscBT seenProcs, flippedProcs; PetscInt *procFIFO, pTop, pBottom; PetscInt *N = NULL, *Noff; PetscSFNode *adj = NULL; PetscBool *val = NULL; PetscMPIInt *recvcounts = NULL, *displs = NULL, *Nc, p, o; PetscMPIInt size = 0; ierr = PetscCalloc1(numComponents, &flipped);CHKERRQ(ierr); if (!rank) {ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);} ierr = PetscCalloc4(size, &recvcounts, size+1, &displs, size, &Nc, size+1, &Noff);CHKERRQ(ierr); ierr = MPI_Gather(&numComponents, 1, MPI_INT, Nc, 1, MPI_INT, 0, comm);CHKERRQ(ierr); for (p = 0; p < size; ++p) { displs[p+1] = displs[p] + Nc[p]; } if (!rank) {ierr = PetscMalloc1(displs[size],&N);CHKERRQ(ierr);} ierr = MPI_Gatherv(numNeighbors, numComponents, MPIU_INT, N, Nc, displs, MPIU_INT, 0, comm);CHKERRQ(ierr); for (p = 0, o = 0; p < size; ++p) { recvcounts[p] = 0; for (c = 0; c < Nc[p]; ++c, ++o) recvcounts[p] += N[o]; displs[p+1] = displs[p] + recvcounts[p]; } if (!rank) {ierr = PetscMalloc2(displs[size], &adj, displs[size], &val);CHKERRQ(ierr);} ierr = MPI_Gatherv(nrankComp, totNeighbors, MPIU_2INT, adj, recvcounts, displs, MPIU_2INT, 0, comm);CHKERRQ(ierr); ierr = MPI_Gatherv(match, totNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm);CHKERRQ(ierr); ierr = PetscFree2(numNeighbors, neighbors);CHKERRQ(ierr); if (!rank) { for (p = 1; p <= size; ++p) {Noff[p] = Noff[p-1] + Nc[p-1];} if (flg) { PetscInt n; for (p = 0, off = 0; p < size; ++p) { for (c = 0; c < Nc[p]; ++c) { ierr = PetscPrintf(PETSC_COMM_SELF, "Proc %d Comp %d:\n", p, c);CHKERRQ(ierr); for (n = 0; n < N[Noff[p]+c]; ++n, ++off) { ierr = PetscPrintf(PETSC_COMM_SELF, " edge (%d, %d) (%d):\n", adj[off].rank, adj[off].index, val[off]);CHKERRQ(ierr); } } } } /* Symmetrize the graph */ ierr = MatCreate(PETSC_COMM_SELF, &G);CHKERRQ(ierr); ierr = MatSetSizes(G, Noff[size], Noff[size], Noff[size], Noff[size]);CHKERRQ(ierr); ierr = MatSetUp(G);CHKERRQ(ierr); for (p = 0, off = 0; p < size; ++p) { for (c = 0; c < Nc[p]; ++c) { const PetscInt r = Noff[p]+c; PetscInt n; for (n = 0; n < N[r]; ++n, ++off) { const PetscInt q = Noff[adj[off].rank] + adj[off].index; const PetscScalar o = val[off] ? 1.0 : 0.0; ierr = MatSetValues(G, 1, &r, 1, &q, &o, INSERT_VALUES);CHKERRQ(ierr); ierr = MatSetValues(G, 1, &q, 1, &r, &o, INSERT_VALUES);CHKERRQ(ierr); } } } ierr = MatAssemblyBegin(G, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(G, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = PetscBTCreate(Noff[size], &seenProcs);CHKERRQ(ierr); ierr = PetscBTMemzero(Noff[size], seenProcs);CHKERRQ(ierr); ierr = PetscBTCreate(Noff[size], &flippedProcs);CHKERRQ(ierr); ierr = PetscBTMemzero(Noff[size], flippedProcs);CHKERRQ(ierr); ierr = PetscMalloc1(Noff[size], &procFIFO);CHKERRQ(ierr); pTop = pBottom = 0; for (p = 0; p < Noff[size]; ++p) { if (PetscBTLookup(seenProcs, p)) continue; /* Initialize FIFO with next proc */ procFIFO[pBottom++] = p; ierr = PetscBTSet(seenProcs, p);CHKERRQ(ierr); /* Consider each proc in FIFO */ while (pTop < pBottom) { const PetscScalar *ornt; const PetscInt *neighbors; PetscInt proc, nproc, seen, flippedA, flippedB, mismatch, numNeighbors, n; proc = procFIFO[pTop++]; flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0; ierr = MatGetRow(G, proc, &numNeighbors, &neighbors, &ornt);CHKERRQ(ierr); /* Loop over neighboring procs */ for (n = 0; n < numNeighbors; ++n) { nproc = neighbors[n]; mismatch = PetscRealPart(ornt[n]) > 0.5 ? 0 : 1; seen = PetscBTLookup(seenProcs, nproc); flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0; if (mismatch ^ (flippedA ^ flippedB)) { if (seen) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %d and %d do not match: Fault mesh is non-orientable", proc, nproc); if (!flippedB) { ierr = PetscBTSet(flippedProcs, nproc);CHKERRQ(ierr); } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable"); } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable"); if (!seen) { procFIFO[pBottom++] = nproc; ierr = PetscBTSet(seenProcs, nproc);CHKERRQ(ierr); } } } } ierr = PetscFree(procFIFO);CHKERRQ(ierr); ierr = MatDestroy(&G);CHKERRQ(ierr); ierr = PetscFree2(adj, val);CHKERRQ(ierr); ierr = PetscBTDestroy(&seenProcs);CHKERRQ(ierr); } /* Scatter flip flags */ { PetscBool *flips = NULL; if (!rank) { ierr = PetscMalloc1(Noff[size], &flips);CHKERRQ(ierr); for (p = 0; p < Noff[size]; ++p) { flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE; if (flg && flips[p]) {ierr = PetscPrintf(comm, "Flipping Proc+Comp %d:\n", p);CHKERRQ(ierr);} } for (p = 0; p < size; ++p) { displs[p+1] = displs[p] + Nc[p]; } } ierr = MPI_Scatterv(flips, Nc, displs, MPIU_BOOL, flipped, numComponents, MPIU_BOOL, 0, comm);CHKERRQ(ierr); ierr = PetscFree(flips);CHKERRQ(ierr); } if (!rank) {ierr = PetscBTDestroy(&flippedProcs);CHKERRQ(ierr);} ierr = PetscFree(N);CHKERRQ(ierr); ierr = PetscFree4(recvcounts, displs, Nc, Noff);CHKERRQ(ierr); ierr = PetscFree2(nrankComp, match);CHKERRQ(ierr); /* Decide whether to flip cells in each component */ for (c = 0; c < cEnd-cStart; ++c) {if (flipped[cellComp[c]]) {ierr = PetscBTNegate(flippedCells, c);CHKERRQ(ierr);}} ierr = PetscFree(flipped);CHKERRQ(ierr); } if (flg) { PetscViewer v; ierr = PetscViewerASCIIGetStdout(comm, &v);CHKERRQ(ierr); ierr = PetscViewerASCIIPushSynchronized(v);CHKERRQ(ierr); ierr = PetscViewerASCIISynchronizedPrintf(v, "[%d]BT for parallel flipped cells:\n", rank);CHKERRQ(ierr); ierr = PetscBTView(cEnd-cStart, flippedCells, v);CHKERRQ(ierr); ierr = PetscViewerFlush(v);CHKERRQ(ierr); ierr = PetscViewerASCIIPopSynchronized(v);CHKERRQ(ierr); } /* Reverse flipped cells in the mesh */ for (c = cStart; c < cEnd; ++c) { if (PetscBTLookup(flippedCells, c-cStart)) { ierr = DMPlexReverseCell(dm, c);CHKERRQ(ierr); } } ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr); ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr); ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr); ierr = PetscFree2(numNeighbors, neighbors);CHKERRQ(ierr); ierr = PetscFree2(rorntComp, lorntComp);CHKERRQ(ierr); ierr = PetscFree3(faceFIFO, cellComp, faceComp);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@C DMPlexDistribute - Distributes the mesh and any associated sections. Not Collective Input Parameter: + dm - The original DMPlex object . partitioner - The partitioning package, or NULL for the default - overlap - The overlap of partitions, 0 is the default Output Parameter: + sf - The PetscSF used for point distribution - parallelMesh - The distributed DMPlex object, or NULL Note: If the mesh was not distributed, the return value is NULL. The user can control the definition of adjacency for the mesh using DMPlexGetAdjacencyUseCone() and DMPlexSetAdjacencyUseClosure(). They should choose the combination appropriate for the function representation on the mesh. Level: intermediate .keywords: mesh, elements .seealso: DMPlexCreate(), DMPlexDistributeByFace(), DMPlexSetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure() @*/ PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel) { DM_Plex *mesh = (DM_Plex*) dm->data, *pmesh; MPI_Comm comm; const PetscInt height = 0; PetscInt dim, numRemoteRanks; IS origCellPart, origPart, cellPart, part; PetscSection origCellPartSection, origPartSection, cellPartSection, partSection; PetscSFNode *remoteRanks; PetscSF partSF, pointSF, coneSF; ISLocalToGlobalMapping renumbering; PetscSection originalConeSection, newConeSection; PetscInt *remoteOffsets; PetscInt *cones, *newCones, newConesSize; PetscBool flg; PetscMPIInt rank, numProcs, p; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); if (sf) PetscValidPointer(sf,4); PetscValidPointer(dmParallel,5); ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr); *dmParallel = NULL; if (numProcs == 1) PetscFunctionReturn(0); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */ ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr); if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented"); ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr); /* Create SF assuming a serial partition for all processes: Could check for IS length here */ if (!rank) numRemoteRanks = numProcs; else numRemoteRanks = 0; ierr = PetscMalloc1(numRemoteRanks, &remoteRanks);CHKERRQ(ierr); for (p = 0; p < numRemoteRanks; ++p) { remoteRanks[p].rank = p; remoteRanks[p].index = 0; } ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr); ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr); ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = ISView(cellPart, NULL);CHKERRQ(ierr); if (origCellPart) { ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr); ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = ISView(origCellPart, NULL);CHKERRQ(ierr); } ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr); } /* Close the partition over the mesh */ ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr); ierr = ISDestroy(&cellPart);CHKERRQ(ierr); ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr); /* Create new mesh */ ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr); ierr = DMSetDimension(*dmParallel, dim);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr); pmesh = (DM_Plex*) (*dmParallel)->data; /* Distribute sieve points and the global point numbering (replaces creating remote bases) */ ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr); ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = ISView(part, NULL);CHKERRQ(ierr); ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr); ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr); } ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr); ierr = PetscLogEventBegin(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr); /* Distribute cone section */ ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr); ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr); ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr); ierr = DMSetUp(*dmParallel);CHKERRQ(ierr); { PetscInt pStart, pEnd, p; ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt coneSize; ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr); pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize); } } /* Communicate and renumber cones */ ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr); ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr); ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr); ierr = ISGlobalToLocalMappingApplyBlock(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr); ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr); ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr); ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr); } ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr); ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr); ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr); ierr = PetscLogEventEnd(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr); /* Create supports and stratify sieve */ { PetscInt pStart, pEnd; ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr); } ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr); ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr); /* Create point SF for parallel mesh */ ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr); { const PetscInt *leaves; PetscSFNode *remotePoints, *rowners, *lowners; PetscInt numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints; PetscInt pStart, pEnd; ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr); ierr = PetscMalloc2(numRoots,&rowners,numLeaves,&lowners);CHKERRQ(ierr); for (p=0; p<numRoots; p++) { rowners[p].rank = -1; rowners[p].index = -1; } if (origCellPart) { /* Make sure points in the original partition are not assigned to other procs */ const PetscInt *origPoints; ierr = DMPlexCreatePartitionClosure(dm, origCellPartSection, origCellPart, &origPartSection, &origPart);CHKERRQ(ierr); ierr = ISGetIndices(origPart, &origPoints);CHKERRQ(ierr); for (p = 0; p < numProcs; ++p) { PetscInt dof, off, d; ierr = PetscSectionGetDof(origPartSection, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(origPartSection, p, &off);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { rowners[origPoints[d]].rank = p; } } ierr = ISRestoreIndices(origPart, &origPoints);CHKERRQ(ierr); ierr = ISDestroy(&origPart);CHKERRQ(ierr); ierr = PetscSectionDestroy(&origPartSection);CHKERRQ(ierr); } ierr = ISDestroy(&origCellPart);CHKERRQ(ierr); ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr); ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); for (p = 0; p < numLeaves; ++p) { if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */ lowners[p].rank = rank; lowners[p].index = leaves ? leaves[p] : p; } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */ lowners[p].rank = -2; lowners[p].index = -2; } } for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */ rowners[p].rank = -3; rowners[p].index = -3; } ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr); ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr); ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); for (p = 0; p < numLeaves; ++p) { if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed"); if (lowners[p].rank != rank) ++numGhostPoints; } ierr = PetscMalloc1(numGhostPoints, &ghostPoints);CHKERRQ(ierr); ierr = PetscMalloc1(numGhostPoints, &remotePoints);CHKERRQ(ierr); for (p = 0, gp = 0; p < numLeaves; ++p) { if (lowners[p].rank != rank) { ghostPoints[gp] = leaves ? leaves[p] : p; remotePoints[gp].rank = lowners[p].rank; remotePoints[gp].index = lowners[p].index; ++gp; } } ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr); ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr); } pmesh->useCone = mesh->useCone; pmesh->useClosure = mesh->useClosure; pmesh->useAnchors = mesh->useAnchors; ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr); /* Distribute Coordinates */ { PetscSection originalCoordSection, newCoordSection; Vec originalCoordinates, newCoordinates; PetscInt bs; const char *name; const PetscReal *maxCell, *L; ierr = DMGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr); ierr = DMGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr); ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr); ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr); ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr); ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr); ierr = VecGetBlockSize(originalCoordinates, &bs);CHKERRQ(ierr); ierr = VecSetBlockSize(newCoordinates, bs);CHKERRQ(ierr); ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr); ierr = DMGetPeriodicity(dm, &maxCell, &L);CHKERRQ(ierr); if (L) {ierr = DMSetPeriodicity(*dmParallel, maxCell, L);CHKERRQ(ierr);} } /* Distribute labels */ ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr); { DMLabel next = mesh->labels, newNext = pmesh->labels; PetscInt numLabels = 0, l; /* Bcast number of labels */ while (next) {++numLabels; next = next->next;} ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); next = mesh->labels; for (l = 0; l < numLabels; ++l) { DMLabel labelNew; PetscBool isdepth; /* Skip "depth" because it is recreated */ if (!rank) {ierr = PetscStrcmp(next->name, "depth", &isdepth);CHKERRQ(ierr);} ierr = MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr); if (isdepth) {if (!rank) next = next->next; continue;} ierr = DMLabelDistribute(next, partSection, part, renumbering, &labelNew);CHKERRQ(ierr); /* Insert into list */ if (newNext) newNext->next = labelNew; else pmesh->labels = labelNew; newNext = labelNew; if (!rank) next = next->next; } } ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr); /* Setup hybrid structure */ { const PetscInt *gpoints; PetscInt depth, n, d; for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];} ierr = MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingGetSize(renumbering, &n);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);CHKERRQ(ierr); ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); for (d = 0; d <= dim; ++d) { PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p; if (pmax < 0) continue; ierr = DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);CHKERRQ(ierr); ierr = MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);CHKERRQ(ierr); for (p = 0; p < n; ++p) { const PetscInt point = gpoints[p]; if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax; } if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax; else pmesh->hybridPointMax[d] = -1; } ierr = ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);CHKERRQ(ierr); } /* Set up tree */ { DM refTree; PetscSection origParentSection, newParentSection; PetscInt *origParents, *origChildIDs; ierr = DMPlexGetReferenceTree(dm,&refTree);CHKERRQ(ierr); ierr = DMPlexSetReferenceTree(*dmParallel,refTree);CHKERRQ(ierr); ierr = DMPlexGetTree(dm,&origParentSection,&origParents,&origChildIDs,NULL,NULL);CHKERRQ(ierr); if (origParentSection) { PetscInt pStart, pEnd; PetscInt *newParents, *newChildIDs; PetscInt *remoteOffsetsParents, newParentSize; PetscSF parentSF; ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)*dmParallel),&newParentSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(newParentSection,pStart,pEnd);CHKERRQ(ierr); ierr = PetscSFDistributeSection(pointSF, origParentSection, &remoteOffsetsParents, newParentSection);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(pointSF, origParentSection, remoteOffsetsParents, newParentSection, &parentSF);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(newParentSection,&newParentSize);CHKERRQ(ierr); ierr = PetscMalloc2(newParentSize,&newParents,newParentSize,&newChildIDs);CHKERRQ(ierr); ierr = PetscSFBcastBegin(parentSF, MPIU_INT, origParents, newParents);CHKERRQ(ierr); ierr = PetscSFBcastEnd(parentSF, MPIU_INT, origParents, newParents);CHKERRQ(ierr); ierr = PetscSFBcastBegin(parentSF, MPIU_INT, origChildIDs, newChildIDs);CHKERRQ(ierr); ierr = PetscSFBcastEnd(parentSF, MPIU_INT, origChildIDs, newChildIDs);CHKERRQ(ierr); ierr = ISGlobalToLocalMappingApplyBlock(renumbering,IS_GTOLM_MASK, newParentSize, newParents, NULL, newParents);CHKERRQ(ierr); ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-parents_view", &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(comm, "Serial Parent Section: \n");CHKERRQ(ierr); ierr = PetscSectionView(origParentSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Parallel Parent Section: \n");CHKERRQ(ierr); ierr = PetscSectionView(newParentSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscSFView(parentSF, NULL);CHKERRQ(ierr); } ierr = DMPlexSetTree(*dmParallel,newParentSection,newParents,newChildIDs);CHKERRQ(ierr); ierr = PetscSectionDestroy(&newParentSection);CHKERRQ(ierr); ierr = PetscFree2(newParents,newChildIDs);CHKERRQ(ierr); ierr = PetscSFDestroy(&parentSF);CHKERRQ(ierr); } } /* Cleanup Partition */ ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr); ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr); ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr); ierr = ISDestroy(&part);CHKERRQ(ierr); /* Copy BC */ ierr = DMPlexCopyBoundary(dm, *dmParallel);CHKERRQ(ierr); /* Cleanup */ if (sf) {*sf = pointSF;} else {ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);} ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr); ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) { PetscInt dim = user->dim; PetscBool interpolate = user->interpolate; PetscReal refinementLimit = user->refinementLimit; PetscBool cellSimplex = user->cellSimplex; PetscBool cellWedge = user->cellWedge; PetscBool simplex2tensor = user->simplex2tensor; const char *filename = user->filename; const char *bdfilename = user->bdfilename; const char *extfilename = user->extfilename; PetscBool testp4est_seq = user->testp4est[0]; PetscBool testp4est_par = user->testp4est[1]; PetscInt triSizes_n2[2] = {4, 4}; PetscInt triPoints_n2[8] = {3, 5, 6, 7, 0, 1, 2, 4}; PetscInt triSizes_n8[8] = {1, 1, 1, 1, 1, 1, 1, 1}; PetscInt triPoints_n8[8] = {0, 1, 2, 3, 4, 5, 6, 7}; PetscInt quadSizes[2] = {2, 2}; PetscInt quadPoints[4] = {2, 3, 0, 1}; PetscInt gmshSizes_n3[3] = {14, 14, 14}; PetscInt gmshPoints_n3[42] = {1, 2, 4, 5, 9, 10, 11, 15, 16, 20, 21, 27, 28, 29, 3, 8, 12, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 6, 7, 13, 14, 17, 18, 19, 22, 23, 24, 25, 26, 41}; PetscInt fluentSizes_n3[3] = {50, 50, 50}; PetscInt fluentPoints_n3[150] = { 5, 6, 7, 8, 12, 14, 16, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 50, 51, 80, 81, 89, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 104, 121, 122, 124, 125, 126, 127, 128, 129, 131, 133, 143, 144, 145, 147, 1, 3, 4, 9, 10, 17, 18, 19, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 47, 61, 71, 72, 73, 74, 75, 76, 77, 78, 79, 86, 87, 88, 90, 92, 113, 115, 116, 117, 118, 119, 120, 123, 138, 140, 141, 142, 146, 148, 149, 0, 2, 11, 13, 15, 20, 21, 22, 23, 49, 52, 53, 54, 55, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 82, 83, 84, 85, 102, 103, 105, 106, 107, 108, 109, 110, 111, 112, 114, 130, 132, 134, 135, 136, 137, 139}; size_t len, bdlen, extlen; PetscMPIInt rank, size; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscLogEventBegin(user->createMeshEvent,0,0,0,0);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); ierr = PetscStrlen(filename, &len);CHKERRQ(ierr); ierr = PetscStrlen(bdfilename, &bdlen);CHKERRQ(ierr); ierr = PetscStrlen(extfilename, &extlen);CHKERRQ(ierr); ierr = PetscLogStagePush(user->stages[STAGE_LOAD]);CHKERRQ(ierr); if (len) { ierr = DMPlexCreateFromFile(comm, filename, interpolate, dm);CHKERRQ(ierr); } else if (bdlen) { DM boundary; ierr = DMPlexCreateFromFile(comm, bdfilename, interpolate, &boundary);CHKERRQ(ierr); ierr = DMPlexGenerate(boundary, NULL, interpolate, dm);CHKERRQ(ierr); ierr = DMDestroy(&boundary);CHKERRQ(ierr); } else if (extlen) { DM edm; ierr = DMPlexCreateFromFile(comm, extfilename, interpolate, &edm);CHKERRQ(ierr); ierr = DMPlexExtrude(edm, user->extrude_layers, user->extrude_thickness, PETSC_TRUE, interpolate, dm);CHKERRQ(ierr); ierr = DMDestroy(&edm);CHKERRQ(ierr); } else { switch (user->domainShape) { case BOX: if (cellWedge) { if (dim != 3) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Dimension must be 3 for a wedge mesh, not %D", dim); ierr = DMPlexCreateWedgeBoxMesh(comm, user->domainBoxSizes, user->domainBoxL, user->domainBoxU, user->periodicity, PETSC_FALSE, interpolate, dm);CHKERRQ(ierr); } else { ierr = DMPlexCreateBoxMesh(comm, dim, cellSimplex, user->domainBoxSizes, user->domainBoxL, user->domainBoxU, user->periodicity, interpolate, dm);CHKERRQ(ierr); } break; case CYLINDER: if (cellSimplex) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Cannot mesh a cylinder with simplices"); if (dim != 3) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Dimension must be 3 for a cylinder mesh, not %D", dim); if (cellWedge) { ierr = DMPlexCreateWedgeCylinderMesh(comm, 6, interpolate, dm);CHKERRQ(ierr); } else { ierr = DMPlexCreateHexCylinderMesh(comm, 3, user->periodicity[2], dm);CHKERRQ(ierr); } break; default: SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Unknown domain shape %D", user->domainShape); } } ierr = DMLocalizeCoordinates(*dm);CHKERRQ(ierr); /* needed for periodic */ ierr = DMViewFromOptions(*dm,NULL,"-init_dm_view");CHKERRQ(ierr); ierr = DMGetDimension(*dm,&dim);CHKERRQ(ierr); if (testp4est_seq) { #if defined(PETSC_HAVE_P4EST) DM dmConv = NULL; ierr = DMPlexSetRefinementUniform(*dm, PETSC_TRUE);CHKERRQ(ierr); ierr = DMPlexRefineSimplexToTensor(*dm, &dmConv);CHKERRQ(ierr); if (dmConv) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } user->cellSimplex = PETSC_FALSE; ierr = DMConvert(*dm,dim == 2 ? DMP4EST : DMP8EST,&dmConv);CHKERRQ(ierr); if (dmConv) { ierr = DMSetFromOptions(dmConv);CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } ierr = DMSetUp(*dm);CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-conv_seq_1_dm_view");CHKERRQ(ierr); ierr = DMConvert(*dm,DMPLEX,&dmConv);CHKERRQ(ierr); if (dmConv) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } ierr = DMViewFromOptions(*dm, NULL, "-conv_seq_2_dm_view");CHKERRQ(ierr); #else SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Recompile with --download-p4est"); #endif } ierr = PetscLogStagePop();CHKERRQ(ierr); if (!testp4est_seq) { DM refinedMesh = NULL; DM distributedMesh = NULL; if (user->testPartition) { const PetscInt *sizes = NULL; const PetscInt *points = NULL; PetscPartitioner part; if (!rank) { if (dim == 2 && cellSimplex && size == 2) { sizes = triSizes_n2; points = triPoints_n2; } else if (dim == 2 && cellSimplex && size == 8) { sizes = triSizes_n8; points = triPoints_n8; } else if (dim == 2 && !cellSimplex && size == 2) { sizes = quadSizes; points = quadPoints; } else if (dim == 2 && size == 3) { PetscInt Nc; ierr = DMPlexGetHeightStratum(*dm, 0, NULL, &Nc);CHKERRQ(ierr); if (Nc == 42) { /* Gmsh 3 & 4 */ sizes = gmshSizes_n3; points = gmshPoints_n3; } else if (Nc == 150) { /* Fluent 1 */ sizes = fluentSizes_n3; points = fluentPoints_n3; } else if (Nc == 42) { /* Med 1 */ } else if (Nc == 161) { /* Med 3 */ } } } ierr = DMPlexGetPartitioner(*dm, &part);CHKERRQ(ierr); ierr = PetscPartitionerSetType(part, PETSCPARTITIONERSHELL);CHKERRQ(ierr); ierr = PetscPartitionerShellSetPartition(part, size, sizes, points);CHKERRQ(ierr); } else { PetscPartitioner part; ierr = DMPlexGetPartitioner(*dm,&part);CHKERRQ(ierr); ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr); } /* Distribute mesh over processes */ ierr = PetscLogStagePush(user->stages[STAGE_DISTRIBUTE]);CHKERRQ(ierr); ierr = DMPlexDistribute(*dm, 0, NULL, &distributedMesh);CHKERRQ(ierr); if (distributedMesh) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = distributedMesh; } ierr = PetscLogStagePop();CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-distributed_dm_view");CHKERRQ(ierr); /* Refine mesh using a volume constraint */ ierr = PetscLogStagePush(user->stages[STAGE_REFINE]);CHKERRQ(ierr); ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); ierr = DMPlexSetRefinementLimit(*dm, refinementLimit);CHKERRQ(ierr); ierr = DMRefine(*dm, comm, &refinedMesh);CHKERRQ(ierr); if (refinedMesh) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = refinedMesh; } ierr = PetscLogStagePop();CHKERRQ(ierr); } ierr = PetscLogStagePush(user->stages[STAGE_REFINE]);CHKERRQ(ierr); ierr = DMSetFromOptions(*dm);CHKERRQ(ierr); ierr = PetscLogStagePop();CHKERRQ(ierr); if (testp4est_par) { #if defined(PETSC_HAVE_P4EST) DM dmConv = NULL; ierr = DMPlexSetRefinementUniform(*dm, PETSC_TRUE);CHKERRQ(ierr); ierr = DMPlexRefineSimplexToTensor(*dm, &dmConv);CHKERRQ(ierr); if (dmConv) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } user->cellSimplex = PETSC_FALSE; ierr = DMConvert(*dm,dim == 2 ? DMP4EST : DMP8EST,&dmConv);CHKERRQ(ierr); ierr = PetscObjectSetOptionsPrefix((PetscObject) dmConv, "conv_par_1_");CHKERRQ(ierr); if (dmConv) { ierr = DMSetFromOptions(dmConv);CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } ierr = DMSetUp(*dm);CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); ierr = DMConvert(*dm,DMPLEX,&dmConv);CHKERRQ(ierr); ierr = PetscObjectSetOptionsPrefix((PetscObject) dmConv, "conv_par_2_");CHKERRQ(ierr); if (dmConv) { ierr = DMSetFromOptions(dmConv);CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = dmConv; } ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); #else SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Recompile with --download-p4est"); #endif } if (user->overlap) { DM overlapMesh = NULL; /* Add the level-1 overlap to refined mesh */ ierr = PetscLogStagePush(user->stages[STAGE_OVERLAP]);CHKERRQ(ierr); ierr = DMPlexDistributeOverlap(*dm, 1, NULL, &overlapMesh);CHKERRQ(ierr); if (overlapMesh) { ierr = DMView(overlapMesh, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = overlapMesh; } ierr = PetscLogStagePop();CHKERRQ(ierr); } if (simplex2tensor) { DM rdm = NULL; ierr = DMPlexSetRefinementUniform(*dm, PETSC_TRUE);CHKERRQ(ierr); ierr = DMPlexRefineSimplexToTensor(*dm, &rdm);CHKERRQ(ierr); if (rdm) { ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = rdm; } user->cellSimplex = PETSC_FALSE; } ierr = PetscObjectSetName((PetscObject) *dm, "Simplicial Mesh");CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); ierr = PetscLogEventEnd(user->createMeshEvent,0,0,0,0);CHKERRQ(ierr); user->dm = *dm; PetscFunctionReturn(0); }
/* - Checks face match - Flips non-matching - Inserts faces of support cells in FIFO */ static PetscErrorCode DMPlexCheckFace_Internal(DM dm, PetscInt *faceFIFO, PetscInt *fTop, PetscInt *fBottom, PetscInt cStart, PetscInt fStart, PetscInt fEnd, PetscBT seenCells, PetscBT flippedCells, PetscBT seenFaces) { const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB; PetscInt supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1; PetscInt face, dim, seenA, flippedA, seenB, flippedB, mismatch, c; PetscErrorCode ierr; PetscFunctionBegin; face = faceFIFO[(*fTop)++]; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr); if (supportSize < 2) PetscFunctionReturn(0); if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize); seenA = PetscBTLookup(seenCells, support[0]-cStart); flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0; seenB = PetscBTLookup(seenCells, support[1]-cStart); flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0; ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr); ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr); ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr); ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr); ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr); for (c = 0; c < coneSizeA; ++c) { if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) { faceFIFO[(*fBottom)++] = coneA[c]; ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr); } if (coneA[c] == face) posA = c; if (*fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], *fBottom, fEnd-fStart); } if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]); for (c = 0; c < coneSizeB; ++c) { if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) { faceFIFO[(*fBottom)++] = coneB[c]; ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr); } if (coneB[c] == face) posB = c; if (*fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], *fBottom, fEnd-fStart); } if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]); if (dim == 1) { mismatch = posA == posB; } else { mismatch = coneOA[posA] == coneOB[posB]; } if (mismatch ^ (flippedA ^ flippedB)) { if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]); if (!seenA && !flippedA) { ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr); } else if (!seenB && !flippedB) { ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr); } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable"); } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable"); ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr); ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode CreateMesh(MPI_Comm comm, PetscInt testNum, AppCtx *user, DM *dm) { PetscInt dim = user->dim; PetscBool cellSimplex = user->cellSimplex; PetscBool useGenerator = user->useGenerator; const char *filename = user->filename; size_t len; PetscMPIInt rank; PetscErrorCode ierr; PetscFunctionBegin; ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = PetscStrlen(filename, &len);CHKERRQ(ierr); if (len) { ierr = DMPlexCreateFromFile(comm, filename, PETSC_FALSE, dm);CHKERRQ(ierr); ierr = DMGetDimension(*dm, &dim);CHKERRQ(ierr); } else if (useGenerator) { if (cellSimplex) { ierr = DMPlexCreateBoxMesh(comm, dim, dim == 2 ? 2 : 1, PETSC_FALSE, dm);CHKERRQ(ierr); } else { const PetscInt cells[3] = {2, 2, 2}; ierr = DMPlexCreateHexBoxMesh(comm, dim, cells, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, dm);CHKERRQ(ierr); } } else { ierr = DMCreate(comm, dm);CHKERRQ(ierr); ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr); ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr); switch (dim) { case 2: if (cellSimplex) { ierr = CreateSimplex_2D(comm, *dm);CHKERRQ(ierr); } else { ierr = CreateQuad_2D(comm, testNum, *dm);CHKERRQ(ierr); } break; case 3: if (cellSimplex) { ierr = CreateSimplex_3D(comm, *dm);CHKERRQ(ierr); } else { ierr = CreateHex_3D(comm, *dm);CHKERRQ(ierr); } break; default: SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %d", dim); } } { DM interpolatedMesh = NULL; ierr = CheckMesh(*dm, user);CHKERRQ(ierr); ierr = DMPlexInterpolate(*dm, &interpolatedMesh);CHKERRQ(ierr); ierr = DMPlexCopyCoordinates(*dm, interpolatedMesh);CHKERRQ(ierr); ierr = CompareCones(*dm, interpolatedMesh);CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = interpolatedMesh; } { DM distributedMesh = NULL; /* Distribute mesh over processes */ ierr = DMPlexDistribute(*dm, 0, NULL, &distributedMesh);CHKERRQ(ierr); if (distributedMesh) { ierr = DMViewFromOptions(distributedMesh, NULL, "-dm_view");CHKERRQ(ierr); ierr = DMDestroy(dm);CHKERRQ(ierr); *dm = distributedMesh; } } ierr = PetscObjectSetName((PetscObject) *dm, "Interpolated Mesh");CHKERRQ(ierr); ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); user->dm = *dm; PetscFunctionReturn(0); }
PetscErrorCode PetscFEGetTabulation_Composite(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal *B, PetscReal *D, PetscReal *H) { PetscFE_Composite *cmp = (PetscFE_Composite *) fem->data; DM dm; PetscInt pdim; /* Dimension of FE space P */ PetscInt spdim; /* Dimension of subelement FE space P */ PetscInt dim; /* Spatial dimension */ PetscInt comp; /* Field components */ PetscInt *subpoints; PetscReal *tmpB, *tmpD, *tmpH, *subpoint; PetscInt p, s, d, e, j, k; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = PetscSpaceGetDimension(fem->basisSpace, &spdim);CHKERRQ(ierr); ierr = PetscDualSpaceGetDimension(fem->dualSpace, &pdim);CHKERRQ(ierr); ierr = PetscFEGetNumComponents(fem, &comp);CHKERRQ(ierr); /* Divide points into subelements */ ierr = DMGetWorkArray(dm, npoints, MPIU_INT, &subpoints);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, dim, MPIU_REAL, &subpoint);CHKERRQ(ierr); for (p = 0; p < npoints; ++p) { for (s = 0; s < cmp->numSubelements; ++s) { PetscBool inside; /* Apply transform, and check that point is inside cell */ for (d = 0; d < dim; ++d) { subpoint[d] = -1.0; for (e = 0; e < dim; ++e) subpoint[d] += cmp->invjac[(s*dim + d)*dim+e]*(points[p*dim+e] - cmp->v0[s*dim+e]); } ierr = CellRefinerInCellTest_Internal(cmp->cellRefiner, subpoint, &inside);CHKERRQ(ierr); if (inside) {subpoints[p] = s; break;} } if (s >= cmp->numSubelements) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d was not found in any subelement", p); } ierr = DMRestoreWorkArray(dm, dim, MPIU_REAL, &subpoint);CHKERRQ(ierr); /* Evaluate the prime basis functions at all points */ if (B) {ierr = DMGetWorkArray(dm, npoints*spdim, MPIU_REAL, &tmpB);CHKERRQ(ierr);} if (D) {ierr = DMGetWorkArray(dm, npoints*spdim*dim, MPIU_REAL, &tmpD);CHKERRQ(ierr);} if (H) {ierr = DMGetWorkArray(dm, npoints*spdim*dim*dim, MPIU_REAL, &tmpH);CHKERRQ(ierr);} ierr = PetscSpaceEvaluate(fem->basisSpace, npoints, points, B ? tmpB : NULL, D ? tmpD : NULL, H ? tmpH : NULL);CHKERRQ(ierr); /* Translate to the nodal basis */ if (B) {ierr = PetscMemzero(B, npoints*pdim*comp * sizeof(PetscReal));CHKERRQ(ierr);} if (D) {ierr = PetscMemzero(D, npoints*pdim*comp*dim * sizeof(PetscReal));CHKERRQ(ierr);} if (H) {ierr = PetscMemzero(H, npoints*pdim*comp*dim*dim * sizeof(PetscReal));CHKERRQ(ierr);} for (p = 0; p < npoints; ++p) { const PetscInt s = subpoints[p]; if (B) { /* Multiply by V^{-1} (spdim x spdim) */ for (j = 0; j < spdim; ++j) { const PetscInt i = (p*pdim + cmp->embedding[s*spdim+j])*comp; B[i] = 0.0; for (k = 0; k < spdim; ++k) { B[i] += fem->invV[(s*spdim + k)*spdim+j] * tmpB[p*spdim + k]; } } } if (D) { /* Multiply by V^{-1} (spdim x spdim) */ for (j = 0; j < spdim; ++j) { for (d = 0; d < dim; ++d) { const PetscInt i = ((p*pdim + cmp->embedding[s*spdim+j])*comp + 0)*dim + d; D[i] = 0.0; for (k = 0; k < spdim; ++k) { D[i] += fem->invV[(s*spdim + k)*spdim+j] * tmpD[(p*spdim + k)*dim + d]; } } } } if (H) { /* Multiply by V^{-1} (pdim x pdim) */ for (j = 0; j < spdim; ++j) { for (d = 0; d < dim*dim; ++d) { const PetscInt i = ((p*pdim + cmp->embedding[s*spdim+j])*comp + 0)*dim*dim + d; H[i] = 0.0; for (k = 0; k < spdim; ++k) { H[i] += fem->invV[(s*spdim + k)*spdim+j] * tmpH[(p*spdim + k)*dim*dim + d]; } } } } } ierr = DMRestoreWorkArray(dm, npoints, MPIU_INT, &subpoints);CHKERRQ(ierr); if (B) {ierr = DMRestoreWorkArray(dm, npoints*spdim, MPIU_REAL, &tmpB);CHKERRQ(ierr);} if (D) {ierr = DMRestoreWorkArray(dm, npoints*spdim*dim, MPIU_REAL, &tmpD);CHKERRQ(ierr);} if (H) {ierr = DMRestoreWorkArray(dm, npoints*spdim*dim*dim, MPIU_REAL, &tmpH);CHKERRQ(ierr);} PetscFunctionReturn(0); }
/*@ DMPlexUninterpolate - Take in a mesh with all intermediate faces, edges, etc. and return a cell-vertex mesh Collective on DM Input Parameter: . dm - The complete DMPlex object Output Parameter: . dmUnint - The DMPlex object with only cells and vertices Level: intermediate .keywords: mesh .seealso: DMPlexInterpolate(), DMPlexCreateFromCellList() @*/ PetscErrorCode DMPlexUninterpolate(DM dm, DM *dmUnint) { DM udm; PetscInt dim, vStart, vEnd, cStart, cEnd, c, maxConeSize = 0, *cone; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); if (dim <= 1) { ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); *dmUnint = dm; PetscFunctionReturn(0); } ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); ierr = DMCreate(PetscObjectComm((PetscObject) dm), &udm);CHKERRQ(ierr); ierr = DMSetType(udm, DMPLEX);CHKERRQ(ierr); ierr = DMSetDimension(udm, dim);CHKERRQ(ierr); ierr = DMPlexSetChart(udm, cStart, vEnd);CHKERRQ(ierr); for (c = cStart; c < cEnd; ++c) { PetscInt *closure = NULL, closureSize, cl, coneSize = 0; ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize*2; cl += 2) { const PetscInt p = closure[cl]; if ((p >= vStart) && (p < vEnd)) ++coneSize; } ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); ierr = DMPlexSetConeSize(udm, c, coneSize);CHKERRQ(ierr); maxConeSize = PetscMax(maxConeSize, coneSize); } ierr = DMSetUp(udm);CHKERRQ(ierr); ierr = PetscMalloc1(maxConeSize, &cone);CHKERRQ(ierr); for (c = cStart; c < cEnd; ++c) { PetscInt *closure = NULL, closureSize, cl, coneSize = 0; ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize*2; cl += 2) { const PetscInt p = closure[cl]; if ((p >= vStart) && (p < vEnd)) cone[coneSize++] = p; } ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); ierr = DMPlexSetCone(udm, c, cone);CHKERRQ(ierr); } ierr = PetscFree(cone);CHKERRQ(ierr); ierr = DMPlexSymmetrize(udm);CHKERRQ(ierr); ierr = DMPlexStratify(udm);CHKERRQ(ierr); /* Reduce SF */ { PetscSF sfPoint, sfPointUn; const PetscSFNode *remotePoints; const PetscInt *localPoints; PetscSFNode *remotePointsUn; PetscInt *localPointsUn; PetscInt vEnd, numRoots, numLeaves, l; PetscInt numLeavesUn = 0, n = 0; PetscErrorCode ierr; /* Get original SF information */ ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr); ierr = DMGetPointSF(udm, &sfPointUn);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(dm, 0, NULL, &vEnd);CHKERRQ(ierr); ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr); /* Allocate space for cells and vertices */ for (l = 0; l < numLeaves; ++l) if (localPoints[l] < vEnd) numLeavesUn++; /* Fill in leaves */ if (vEnd >= 0) { ierr = PetscMalloc1(numLeavesUn, &remotePointsUn);CHKERRQ(ierr); ierr = PetscMalloc1(numLeavesUn, &localPointsUn);CHKERRQ(ierr); for (l = 0; l < numLeaves; l++) { if (localPoints[l] < vEnd) { localPointsUn[n] = localPoints[l]; remotePointsUn[n].rank = remotePoints[l].rank; remotePointsUn[n].index = remotePoints[l].index; ++n; } } if (n != numLeavesUn) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent number of leaves %d != %d", n, numLeavesUn); ierr = PetscSFSetGraph(sfPointUn, vEnd, numLeavesUn, localPointsUn, PETSC_OWN_POINTER, remotePointsUn, PETSC_OWN_POINTER);CHKERRQ(ierr); } } *dmUnint = udm; PetscFunctionReturn(0); }
PetscErrorCode DMPlexVTKWriteCells_ASCII(DM dm, FILE *fp, PetscInt *totalCells) { MPI_Comm comm; DMLabel label; IS globalVertexNumbers = NULL; const PetscInt *gvertex; PetscInt dim; PetscInt numCorners = 0, totCorners = 0, maxCorners, *corners; PetscInt numCells = 0, totCells = 0, maxCells, cellHeight; PetscInt numLabelCells, maxLabelCells, cMax, cStart, cEnd, c, vStart, vEnd, v; PetscMPIInt numProcs, rank, proc, tag; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); ierr = PetscCommGetNewTag(comm, &tag);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); if (cMax >= 0) cEnd = PetscMin(cEnd, cMax); ierr = DMPlexGetLabel(dm, "vtk", &label);CHKERRQ(ierr); ierr = DMPlexGetStratumSize(dm, "vtk", 1, &numLabelCells);CHKERRQ(ierr); ierr = MPI_Allreduce(&numLabelCells, &maxLabelCells, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); if (!maxLabelCells) label = NULL; for (c = cStart; c < cEnd; ++c) { PetscInt *closure = NULL; PetscInt closureSize, value; if (label) { ierr = DMLabelGetValue(label, c, &value);CHKERRQ(ierr); if (value != 1) continue; } ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (v = 0; v < closureSize*2; v += 2) { if ((closure[v] >= vStart) && (closure[v] < vEnd)) ++numCorners; } ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); ++numCells; } maxCells = numCells; ierr = MPI_Reduce(&numCells, &totCells, 1, MPIU_INT, MPI_SUM, 0, comm);CHKERRQ(ierr); ierr = MPI_Reduce(&numCells, &maxCells, 1, MPIU_INT, MPI_MAX, 0, comm);CHKERRQ(ierr); ierr = MPI_Reduce(&numCorners, &totCorners, 1, MPIU_INT, MPI_SUM, 0, comm);CHKERRQ(ierr); ierr = MPI_Reduce(&numCorners, &maxCorners, 1, MPIU_INT, MPI_MAX, 0, comm);CHKERRQ(ierr); ierr = DMPlexGetVertexNumbering(dm, &globalVertexNumbers);CHKERRQ(ierr); ierr = ISGetIndices(globalVertexNumbers, &gvertex);CHKERRQ(ierr); ierr = PetscMalloc1(maxCells, &corners);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "CELLS %d %d\n", totCells, totCorners+totCells);CHKERRQ(ierr); if (!rank) { PetscInt *remoteVertices; int *vertices; ierr = PetscMalloc1(maxCorners, &vertices);CHKERRQ(ierr); for (c = cStart, numCells = 0; c < cEnd; ++c) { PetscInt *closure = NULL; PetscInt closureSize, value, nC = 0; if (label) { ierr = DMLabelGetValue(label, c, &value);CHKERRQ(ierr); if (value != 1) continue; } ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (v = 0; v < closureSize*2; v += 2) { if ((closure[v] >= vStart) && (closure[v] < vEnd)) { const PetscInt gv = gvertex[closure[v] - vStart]; vertices[nC++] = gv < 0 ? -(gv+1) : gv; } } ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); corners[numCells++] = nC; ierr = PetscFPrintf(comm, fp, "%d ", nC);CHKERRQ(ierr); ierr = DMPlexInvertCell(dim, nC, vertices);CHKERRQ(ierr); for (v = 0; v < nC; ++v) { ierr = PetscFPrintf(comm, fp, " %d", vertices[v]);CHKERRQ(ierr); } ierr = PetscFPrintf(comm, fp, "\n");CHKERRQ(ierr); } if (numProcs > 1) {ierr = PetscMalloc1(maxCorners+maxCells, &remoteVertices);CHKERRQ(ierr);} for (proc = 1; proc < numProcs; ++proc) { MPI_Status status; ierr = MPI_Recv(&numCorners, 1, MPIU_INT, proc, tag, comm, &status);CHKERRQ(ierr); ierr = MPI_Recv(remoteVertices, numCorners, MPIU_INT, proc, tag, comm, &status);CHKERRQ(ierr); for (c = 0; c < numCorners;) { PetscInt nC = remoteVertices[c++]; for (v = 0; v < nC; ++v, ++c) { vertices[v] = remoteVertices[c]; } ierr = DMPlexInvertCell(dim, nC, vertices);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "%d ", nC);CHKERRQ(ierr); for (v = 0; v < nC; ++v) { ierr = PetscFPrintf(comm, fp, " %d", vertices[v]);CHKERRQ(ierr); } ierr = PetscFPrintf(comm, fp, "\n");CHKERRQ(ierr); } } if (numProcs > 1) {ierr = PetscFree(remoteVertices);CHKERRQ(ierr);} ierr = PetscFree(vertices);CHKERRQ(ierr); } else { PetscInt *localVertices, numSend = numCells+numCorners, k = 0; ierr = PetscMalloc1(numSend, &localVertices);CHKERRQ(ierr); for (c = cStart, numCells = 0; c < cEnd; ++c) { PetscInt *closure = NULL; PetscInt closureSize, value, nC = 0; if (label) { ierr = DMLabelGetValue(label, c, &value);CHKERRQ(ierr); if (value != 1) continue; } ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (v = 0; v < closureSize*2; v += 2) { if ((closure[v] >= vStart) && (closure[v] < vEnd)) { const PetscInt gv = gvertex[closure[v] - vStart]; closure[nC++] = gv < 0 ? -(gv+1) : gv; } } corners[numCells++] = nC; localVertices[k++] = nC; for (v = 0; v < nC; ++v, ++k) { localVertices[k] = closure[v]; } ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); } if (k != numSend) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Invalid number of vertices to send %d should be %d", k, numSend); ierr = MPI_Send(&numSend, 1, MPIU_INT, 0, tag, comm);CHKERRQ(ierr); ierr = MPI_Send(localVertices, numSend, MPIU_INT, 0, tag, comm);CHKERRQ(ierr); ierr = PetscFree(localVertices);CHKERRQ(ierr); } ierr = ISRestoreIndices(globalVertexNumbers, &gvertex);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "CELL_TYPES %d\n", totCells);CHKERRQ(ierr); if (!rank) { PetscInt cellType; for (c = 0; c < numCells; ++c) { ierr = DMPlexVTKGetCellType(dm, dim, corners[c], &cellType);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "%d\n", cellType);CHKERRQ(ierr); } for (proc = 1; proc < numProcs; ++proc) { MPI_Status status; ierr = MPI_Recv(&numCells, 1, MPIU_INT, proc, tag, comm, &status);CHKERRQ(ierr); ierr = MPI_Recv(corners, numCells, MPIU_INT, proc, tag, comm, &status);CHKERRQ(ierr); for (c = 0; c < numCells; ++c) { ierr = DMPlexVTKGetCellType(dm, dim, corners[c], &cellType);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "%d\n", cellType);CHKERRQ(ierr); } } } else { ierr = MPI_Send(&numCells, 1, MPIU_INT, 0, tag, comm);CHKERRQ(ierr); ierr = MPI_Send(corners, numCells, MPIU_INT, 0, tag, comm);CHKERRQ(ierr); } ierr = PetscFree(corners);CHKERRQ(ierr); *totalCells = totCells; PetscFunctionReturn(0); }
PetscErrorCode private_DMSwarmView_XDMF(DM dm,PetscViewer viewer) { PetscBool isswarm = PETSC_FALSE; const char *viewername; char datafile[PETSC_MAX_PATH_LEN]; PetscViewer fviewer; PetscInt k,ng,dim; Vec dvec; long int *bytes = NULL; PetscContainer container = NULL; const char *dmname; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectQuery((PetscObject)viewer,"XDMFViewerContext",(PetscObject*)&container);CHKERRQ(ierr); if (container) { ierr = PetscContainerGetPointer(container,(void**)&bytes);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Valid to find attached data XDMFViewerContext"); ierr = PetscObjectTypeCompare((PetscObject)dm,DMSWARM,&isswarm);CHKERRQ(ierr); if (!isswarm) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Only valid for DMSwarm"); ierr = PetscObjectCompose((PetscObject)viewer,"DMSwarm",(PetscObject)dm);CHKERRQ(ierr); ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscObjectGetName((PetscObject)dm,&dmname);CHKERRQ(ierr); if (!dmname) { ierr = DMGetOptionsPrefix(dm,&dmname);CHKERRQ(ierr); } if (!dmname) { ierr = PetscViewerASCIIPrintf(viewer,"<Grid Name=\"DMSwarm\" GridType=\"Uniform\">\n");CHKERRQ(ierr); } else { ierr = PetscViewerASCIIPrintf(viewer,"<Grid Name=\"DMSwarm[%s]\" GridType=\"Uniform\">\n",dmname);CHKERRQ(ierr); } /* create a sub-viewer for topology, geometry and all data fields */ /* name is viewer.name + "_swarm_fields.pbin" */ ierr = PetscViewerCreate(PetscObjectComm((PetscObject)viewer),&fviewer);CHKERRQ(ierr); ierr = PetscViewerSetType(fviewer,PETSCVIEWERBINARY);CHKERRQ(ierr); ierr = PetscViewerBinarySetSkipHeader(fviewer,PETSC_TRUE);CHKERRQ(ierr); ierr = PetscViewerBinarySetSkipInfo(fviewer,PETSC_TRUE);CHKERRQ(ierr); ierr = PetscViewerFileSetMode(fviewer,FILE_MODE_WRITE);CHKERRQ(ierr); ierr = PetscViewerFileGetName(viewer,&viewername);CHKERRQ(ierr); ierr = private_CreateDataFileNameXDMF(viewername,datafile);CHKERRQ(ierr); ierr = PetscViewerFileSetName(fviewer,datafile);CHKERRQ(ierr); ierr = DMSwarmGetSize(dm,&ng);CHKERRQ(ierr); /* write topology header */ ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"<Topology Dimensions=\"%D\" TopologyType=\"Mixed\">\n",ng);CHKERRQ(ierr); ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"<DataItem Format=\"Binary\" Endian=\"Big\" DataType=\"Int\" Dimensions=\"%D\" Seek=\"%D\">\n",ng*3,bytes[0]);CHKERRQ(ierr); ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"%s\n",datafile);CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"</DataItem>\n");CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"</Topology>\n");CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); /* write topology data */ for (k=0; k<ng; k++) { PetscInt pvertex[3]; pvertex[0] = 1; pvertex[1] = 1; pvertex[2] = k; ierr = PetscViewerBinaryWrite(fviewer,pvertex,3,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr); } bytes[0] += sizeof(PetscInt) * ng * 3; /* write geometry header */ ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); switch (dim) { case 1: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for 1D"); break; case 2: ierr = PetscViewerASCIIPrintf(viewer,"<Geometry Type=\"XY\">\n");CHKERRQ(ierr); break; case 3: ierr = PetscViewerASCIIPrintf(viewer,"<Geometry Type=\"XYZ\">\n");CHKERRQ(ierr); break; } ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"<DataItem Format=\"Binary\" Endian=\"Big\" DataType=\"Float\" Precision=\"8\" Dimensions=\"%D %D\" Seek=\"%D\">\n",ng,dim,bytes[0]);CHKERRQ(ierr); ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"%s\n",datafile);CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"</DataItem>\n");CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer,"</Geometry>\n");CHKERRQ(ierr); ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); /* write geometry data */ ierr = DMSwarmCreateGlobalVectorFromField(dm,DMSwarmPICField_coor,&dvec);CHKERRQ(ierr); ierr = VecView(dvec,fviewer);CHKERRQ(ierr); ierr = DMSwarmDestroyGlobalVectorFromField(dm,DMSwarmPICField_coor,&dvec);CHKERRQ(ierr); bytes[0] += sizeof(PetscReal) * ng * dim; ierr = PetscViewerDestroy(&fviewer);CHKERRQ(ierr); PetscFunctionReturn(0); }
static PetscErrorCode TestCellShape(DM dm) { PetscMPIInt rank; PetscInt dim, c, cStart, cEnd, count = 0; ex1_stats_t stats, globalStats; PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; MPI_Comm comm = PetscObjectComm((PetscObject)dm); DM dmCoarse; PetscErrorCode ierr; PetscFunctionBegin; stats.min = PETSC_MAX_REAL; stats.max = PETSC_MIN_REAL; stats.sum = stats.squaresum = 0.; stats.count = 0; ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); ierr = PetscMalloc2(dim * dim, &J, dim * dim, &invJ);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); for (c = cStart; c < cEnd; c++) { PetscInt i; PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr); for (i = 0; i < dim * dim; i++) { frobJ += J[i] * J[i]; frobInvJ += invJ[i] * invJ[i]; } cond2 = frobJ * frobInvJ; cond = PetscSqrtReal(cond2); stats.min = PetscMin(stats.min,cond); stats.max = PetscMax(stats.max,cond); stats.sum += cond; stats.squaresum += cond2; stats.count++; } { PetscMPIInt blockLengths[2] = {4,1}; MPI_Aint blockOffsets[2] = {offsetof(ex1_stats_t,min),offsetof(ex1_stats_t,count)}; MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; MPI_Op statReduce; ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRQ(ierr); ierr = MPI_Type_commit(&statType);CHKERRQ(ierr); ierr = MPI_Op_create(ex1_stats_reduce, PETSC_TRUE, &statReduce);CHKERRQ(ierr); ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRQ(ierr); ierr = MPI_Op_free(&statReduce);CHKERRQ(ierr); ierr = MPI_Type_free(&statType);CHKERRQ(ierr); } ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); if (!rank) { count = globalStats.count; min = globalStats.min; max = globalStats.max; mean = globalStats.sum / globalStats.count; stdev = PetscSqrtReal(globalStats.squaresum / globalStats.count - mean * mean); } ierr = PetscPrintf(comm,"Mesh with %d cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev); ierr = PetscFree2(J,invJ);CHKERRQ(ierr); ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr); if (dmCoarse) { ierr = TestCellShape(dmCoarse);CHKERRQ(ierr); } PetscFunctionReturn(0); }
int main(int argc, char **argv) { MPI_Comm comm; DM dm; Vec v, nv, rv, coord; PetscBool test_read = PETSC_FALSE, verbose = PETSC_FALSE, flg; PetscViewer hdf5Viewer; PetscInt dim = 2; PetscInt numFields = 1; PetscInt numBC = 0; PetscInt numComp[1] = {2}; PetscInt numDof[3] = {2, 0, 0}; PetscInt bcFields[1] = {0}; IS bcPoints[1] = {NULL}; PetscSection section; PetscReal norm; PetscErrorCode ierr; ierr = PetscInitialize(&argc, &argv, (char *) 0, help);CHKERRQ(ierr); comm = PETSC_COMM_WORLD; ierr = PetscOptionsBegin(PETSC_COMM_WORLD,"","Test Options","none");CHKERRQ(ierr); ierr = PetscOptionsBool("-test_read","Test reading from the HDF5 file","",PETSC_FALSE,&test_read,NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-verbose","print the Vecs","",PETSC_FALSE,&verbose,NULL);CHKERRQ(ierr); ierr = PetscOptionsInt("-dim","the dimension of the problem","",2,&dim,NULL);CHKERRQ(ierr); ierr = PetscOptionsEnd(); ierr = DMPlexCreateBoxMesh(comm, dim, PETSC_TRUE, &dm);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); numDof[0] = dim; ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, NULL, NULL, §ion);CHKERRQ(ierr); ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr); ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); ierr = DMSetUseNatural(dm, PETSC_TRUE);CHKERRQ(ierr); { DM dmDist; ierr = DMPlexDistribute(dm, 0, NULL, &dmDist);CHKERRQ(ierr); if (dmDist) { ierr = DMDestroy(&dm);CHKERRQ(ierr); dm = dmDist; } } ierr = DMCreateGlobalVector(dm, &v);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) v, "V");CHKERRQ(ierr); ierr = DMGetCoordinates(dm, &coord);CHKERRQ(ierr); ierr = VecCopy(coord, v);CHKERRQ(ierr); if (verbose) { PetscInt size, bs; ierr = VecGetSize(v, &size);CHKERRQ(ierr); ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "==== original V in global ordering. size==%d\tblock size=%d\n", size, bs);CHKERRQ(ierr); ierr = VecView(v, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = DMCreateGlobalVector(dm, &nv);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) nv, "NV");CHKERRQ(ierr); ierr = DMPlexGlobalToNaturalBegin(dm, v, nv);CHKERRQ(ierr); ierr = DMPlexGlobalToNaturalEnd(dm, v, nv);CHKERRQ(ierr); if (verbose) { PetscInt size, bs; ierr = VecGetSize(nv, &size);CHKERRQ(ierr); ierr = VecGetBlockSize(nv, &bs);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "==== V in natural ordering. size==%d\tblock size=%d\n", size, bs);CHKERRQ(ierr); ierr = VecView(nv, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = VecViewFromOptions(v, NULL, "-global_vec_view");CHKERRQ(ierr); if (test_read) { ierr = DMCreateGlobalVector(dm, &rv);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) rv, "V");CHKERRQ(ierr); /* Test native read */ ierr = PetscViewerHDF5Open(comm, "V.h5", FILE_MODE_READ, &hdf5Viewer);CHKERRQ(ierr); ierr = PetscViewerPushFormat(hdf5Viewer, PETSC_VIEWER_NATIVE);CHKERRQ(ierr); ierr = VecLoad(rv, hdf5Viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&hdf5Viewer);CHKERRQ(ierr); if (verbose) { PetscInt size, bs; ierr = VecGetSize(rv, &size);CHKERRQ(ierr); ierr = VecGetBlockSize(rv, &bs);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "==== Vector from file. size==%d\tblock size=%d\n", size, bs);CHKERRQ(ierr); ierr = VecView(rv, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = VecEqual(rv, v, &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(PETSC_COMM_WORLD, "V and RV are equal\n");CHKERRQ(ierr); } else { ierr = PetscPrintf(PETSC_COMM_WORLD, "V and RV are not equal\n\n");CHKERRQ(ierr); ierr = VecAXPY(rv, -1.0, v);CHKERRQ(ierr); ierr = VecNorm(rv, NORM_INFINITY, &norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "diff norm is = %g\n", (double) norm);CHKERRQ(ierr); ierr = VecView(rv, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Test raw read */ ierr = PetscViewerHDF5Open(comm, "V.h5", FILE_MODE_READ, &hdf5Viewer);CHKERRQ(ierr); ierr = VecLoad(rv, hdf5Viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&hdf5Viewer);CHKERRQ(ierr); if (verbose) { PetscInt size, bs; ierr = VecGetSize(rv, &size);CHKERRQ(ierr); ierr = VecGetBlockSize(rv, &bs);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "==== Vector from file. size==%d\tblock size=%d\n", size, bs);CHKERRQ(ierr); ierr = VecView(rv, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = VecEqual(rv, nv, &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPrintf(PETSC_COMM_WORLD, "NV and RV are equal\n");CHKERRQ(ierr); } else { ierr = PetscPrintf(PETSC_COMM_WORLD, "NV and RV are not equal\n\n");CHKERRQ(ierr); ierr = VecAXPY(rv, -1.0, v);CHKERRQ(ierr); ierr = VecNorm(rv, NORM_INFINITY, &norm);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD, "diff norm is = %g\n", (double) norm);CHKERRQ(ierr); ierr = VecView(rv, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } ierr = VecDestroy(&rv);CHKERRQ(ierr); } ierr = VecDestroy(&nv);CHKERRQ(ierr); ierr = VecDestroy(&v);CHKERRQ(ierr); ierr = DMDestroy(&dm);CHKERRQ(ierr); ierr = PetscFinalize(); return 0; }
PetscErrorCode DMCoarsen_Plex(DM dm, MPI_Comm comm, DM *dmCoarsened) { DM_Plex *mesh = (DM_Plex*) dm->data; #ifdef PETSC_HAVE_PRAGMATIC DM udm, coordDM; DMLabel bd; Mat A; Vec coordinates, mb, mx; PetscSection coordSection; const PetscScalar *coords; double *coarseCoords; IS bdIS; PetscReal *x, *y, *z, *eqns, *metric; PetscReal coarseRatio = PetscSqr(0.5); const PetscInt *faces; PetscInt *cells, *bdFaces, *bdFaceIds; PetscInt dim, numCorners, cStart, cEnd, numCells, numCoarseCells, c, vStart, vEnd, numVertices, numCoarseVertices, v, numBdFaces, f, maxConeSize, size, bdSize, coff; #endif PetscErrorCode ierr; PetscFunctionBegin; #ifdef PETSC_HAVE_PRAGMATIC if (!mesh->coarseMesh) { ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMGetCoordinateDM(dm, &coordDM);CHKERRQ(ierr); ierr = DMGetDefaultSection(coordDM, &coordSection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); ierr = DMPlexUninterpolate(dm, &udm);CHKERRQ(ierr); ierr = DMPlexGetMaxSizes(udm, &maxConeSize, NULL);CHKERRQ(ierr); numCells = cEnd - cStart; numVertices = vEnd - vStart; ierr = PetscCalloc5(numVertices, &x, numVertices, &y, numVertices, &z, numVertices*PetscSqr(dim), &metric, numCells*maxConeSize, &cells);CHKERRQ(ierr); ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); for (v = vStart; v < vEnd; ++v) { PetscInt off; ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); x[v-vStart] = coords[off+0]; y[v-vStart] = coords[off+1]; if (dim > 2) z[v-vStart] = coords[off+2]; } ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); for (c = 0, coff = 0; c < numCells; ++c) { const PetscInt *cone; PetscInt coneSize, cl; ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr); ierr = DMPlexGetCone(udm, c, &cone);CHKERRQ(ierr); for (cl = 0; cl < coneSize; ++cl) cells[coff++] = cone[cl] - vStart; } switch (dim) { case 2: pragmatic_2d_init(&numVertices, &numCells, cells, x, y); break; case 3: pragmatic_3d_init(&numVertices, &numCells, cells, x, y, z); break; default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No Pragmatic coarsening defined for dimension %d", dim); } /* Create boundary mesh */ ierr = DMLabelCreate("boundary", &bd);CHKERRQ(ierr); ierr = DMPlexMarkBoundaryFaces(dm, bd);CHKERRQ(ierr); ierr = DMLabelGetStratumIS(bd, 1, &bdIS);CHKERRQ(ierr); ierr = DMLabelGetStratumSize(bd, 1, &numBdFaces);CHKERRQ(ierr); ierr = ISGetIndices(bdIS, &faces);CHKERRQ(ierr); for (f = 0, bdSize = 0; f < numBdFaces; ++f) { PetscInt *closure = NULL; PetscInt closureSize, cl; ierr = DMPlexGetTransitiveClosure(dm, faces[f], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize*2; cl += 2) { if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) ++bdSize; } ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); } ierr = PetscMalloc2(bdSize, &bdFaces, numBdFaces, &bdFaceIds);CHKERRQ(ierr); for (f = 0, bdSize = 0; f < numBdFaces; ++f) { PetscInt *closure = NULL; PetscInt closureSize, cl; ierr = DMPlexGetTransitiveClosure(dm, faces[f], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (cl = 0; cl < closureSize*2; cl += 2) { if ((closure[cl] >= vStart) && (closure[cl] < vEnd)) bdFaces[bdSize++] = closure[cl] - vStart; } /* TODO Fix */ bdFaceIds[f] = 1; ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); } ierr = ISDestroy(&bdIS);CHKERRQ(ierr); ierr = DMLabelDestroy(&bd);CHKERRQ(ierr); pragmatic_set_boundary(&numBdFaces, bdFaces, bdFaceIds); /* Create metric */ size = (dim*(dim+1))/2; ierr = PetscMalloc1(PetscSqr(size), &eqns);CHKERRQ(ierr); ierr = MatCreateSeqDense(PETSC_COMM_SELF, size, size, eqns, &A);CHKERRQ(ierr); ierr = MatCreateVecs(A, &mx, &mb);CHKERRQ(ierr); ierr = VecSet(mb, 1.0);CHKERRQ(ierr); for (c = 0; c < numCells; ++c) { const PetscScalar *sol; PetscScalar *cellCoords = NULL; PetscReal e[3], vol; const PetscInt *cone; PetscInt coneSize, cl, i, j, d, r; ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, NULL, &cellCoords);CHKERRQ(ierr); /* Only works for simplices */ for (i = 0, r = 0; i < dim+1; ++i) { for (j = 0; j < i; ++j, ++r) { for (d = 0; d < dim; ++d) e[d] = cellCoords[i*dim+d] - cellCoords[j*dim+d]; /* FORTRAN ORDERING */ if (dim == 2) { eqns[0*size+r] = PetscSqr(e[0]); eqns[1*size+r] = 2.0*e[0]*e[1]; eqns[2*size+r] = PetscSqr(e[1]); } else { eqns[0*size+r] = PetscSqr(e[0]); eqns[1*size+r] = 2.0*e[0]*e[1]; eqns[2*size+r] = 2.0*e[0]*e[2]; eqns[3*size+r] = PetscSqr(e[1]); eqns[4*size+r] = 2.0*e[1]*e[2]; eqns[5*size+r] = PetscSqr(e[2]); } } } ierr = MatSetUnfactored(A);CHKERRQ(ierr); ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, NULL, &cellCoords);CHKERRQ(ierr); ierr = MatLUFactor(A, NULL, NULL, NULL);CHKERRQ(ierr); ierr = MatSolve(A, mb, mx);CHKERRQ(ierr); ierr = VecGetArrayRead(mx, &sol);CHKERRQ(ierr); ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr); ierr = DMPlexGetCone(udm, c, &cone);CHKERRQ(ierr); ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr); for (cl = 0; cl < coneSize; ++cl) { const PetscInt v = cone[cl] - vStart; if (dim == 2) { metric[v*4+0] += vol*coarseRatio*sol[0]; metric[v*4+1] += vol*coarseRatio*sol[1]; metric[v*4+2] += vol*coarseRatio*sol[1]; metric[v*4+3] += vol*coarseRatio*sol[2]; } else { metric[v*9+0] += vol*coarseRatio*sol[0]; metric[v*9+1] += vol*coarseRatio*sol[1]; metric[v*9+3] += vol*coarseRatio*sol[1]; metric[v*9+2] += vol*coarseRatio*sol[2]; metric[v*9+6] += vol*coarseRatio*sol[2]; metric[v*9+4] += vol*coarseRatio*sol[3]; metric[v*9+5] += vol*coarseRatio*sol[4]; metric[v*9+7] += vol*coarseRatio*sol[4]; metric[v*9+8] += vol*coarseRatio*sol[5]; } } ierr = VecRestoreArrayRead(mx, &sol);CHKERRQ(ierr); } for (v = 0; v < numVertices; ++v) { const PetscInt *support; PetscInt supportSize, s; PetscReal vol, totVol = 0.0; ierr = DMPlexGetSupport(udm, v+vStart, &support);CHKERRQ(ierr); ierr = DMPlexGetSupportSize(udm, v+vStart, &supportSize);CHKERRQ(ierr); for (s = 0; s < supportSize; ++s) {ierr = DMPlexComputeCellGeometryFVM(dm, support[s], &vol, NULL, NULL);CHKERRQ(ierr); totVol += vol;} for (s = 0; s < PetscSqr(dim); ++s) metric[v*PetscSqr(dim)+s] /= totVol; } ierr = VecDestroy(&mx);CHKERRQ(ierr); ierr = VecDestroy(&mb);CHKERRQ(ierr); ierr = MatDestroy(&A);CHKERRQ(ierr); ierr = DMDestroy(&udm);CHKERRQ(ierr); ierr = PetscFree(eqns);CHKERRQ(ierr); pragmatic_set_metric(metric); pragmatic_adapt(); /* Read out mesh */ pragmatic_get_info(&numCoarseVertices, &numCoarseCells); ierr = PetscMalloc1(numCoarseVertices*dim, &coarseCoords);CHKERRQ(ierr); switch (dim) { case 2: pragmatic_get_coords_2d(x, y); numCorners = 3; for (v = 0; v < numCoarseVertices; ++v) {coarseCoords[v*2+0] = x[v]; coarseCoords[v*2+1] = y[v];} break; case 3: pragmatic_get_coords_3d(x, y, z); numCorners = 4; for (v = 0; v < numCoarseVertices; ++v) {coarseCoords[v*3+0] = x[v]; coarseCoords[v*3+1] = y[v]; coarseCoords[v*3+2] = z[v];} break; default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No Pragmatic coarsening defined for dimension %d", dim); } pragmatic_get_elements(cells); /* TODO Read out markers for boundary */ ierr = DMPlexCreateFromCellList(PetscObjectComm((PetscObject) dm), dim, numCoarseCells, numCoarseVertices, numCorners, PETSC_TRUE, cells, dim, coarseCoords, &mesh->coarseMesh);CHKERRQ(ierr); pragmatic_finalize(); ierr = PetscFree5(x, y, z, metric, cells);CHKERRQ(ierr); ierr = PetscFree2(bdFaces, bdFaceIds);CHKERRQ(ierr); ierr = PetscFree(coarseCoords);CHKERRQ(ierr); } #endif ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr); *dmCoarsened = mesh->coarseMesh; PetscFunctionReturn(0); }
static PetscErrorCode DMPlexVTKWriteAll_ASCII(DM dm, PetscViewer viewer) { MPI_Comm comm; PetscViewer_VTK *vtk = (PetscViewer_VTK*) viewer->data; FILE *fp; PetscViewerVTKObjectLink link; PetscSection coordSection, globalCoordSection; PetscLayout vLayout; Vec coordinates; PetscReal lengthScale; PetscInt vMax, totVertices, totCells; PetscBool hasPoint = PETSC_FALSE, hasCell = PETSC_FALSE, writePartition = PETSC_FALSE; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); ierr = PetscFOpen(comm, vtk->filename, "wb", &fp);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "# vtk DataFile Version 2.0\n");CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "Simplicial Mesh Example\n");CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "ASCII\n");CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "DATASET UNSTRUCTURED_GRID\n");CHKERRQ(ierr); /* Vertices */ ierr = DMPlexGetScale(dm, PETSC_UNIT_LENGTH, &lengthScale);CHKERRQ(ierr); ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); ierr = PetscSectionCreateGlobalSection(coordSection, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalCoordSection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); if (vMax >= 0) { PetscInt pStart, pEnd, p, localSize = 0; ierr = PetscSectionGetChart(globalCoordSection, &pStart, &pEnd);CHKERRQ(ierr); pEnd = PetscMin(pEnd, vMax); for (p = pStart; p < pEnd; ++p) { PetscInt dof; ierr = PetscSectionGetDof(globalCoordSection, p, &dof);CHKERRQ(ierr); if (dof > 0) ++localSize; } ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)dm), &vLayout);CHKERRQ(ierr); ierr = PetscLayoutSetLocalSize(vLayout, localSize);CHKERRQ(ierr); ierr = PetscLayoutSetBlockSize(vLayout, 1);CHKERRQ(ierr); ierr = PetscLayoutSetUp(vLayout);CHKERRQ(ierr); } else { ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalCoordSection, &vLayout);CHKERRQ(ierr); } ierr = PetscLayoutGetSize(vLayout, &totVertices);CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "POINTS %d double\n", totVertices);CHKERRQ(ierr); ierr = DMPlexVTKWriteSection_ASCII(dm, coordSection, globalCoordSection, coordinates, fp, 3, PETSC_DETERMINE, lengthScale);CHKERRQ(ierr); /* Cells */ ierr = DMPlexVTKWriteCells_ASCII(dm, fp, &totCells);CHKERRQ(ierr); /* Vertex fields */ for (link = vtk->link; link; link = link->next) { if ((link->ft == PETSC_VTK_POINT_FIELD) || (link->ft == PETSC_VTK_POINT_VECTOR_FIELD)) hasPoint = PETSC_TRUE; if ((link->ft == PETSC_VTK_CELL_FIELD) || (link->ft == PETSC_VTK_CELL_VECTOR_FIELD)) hasCell = PETSC_TRUE; } if (hasPoint) { ierr = PetscFPrintf(comm, fp, "POINT_DATA %d\n", totVertices);CHKERRQ(ierr); for (link = vtk->link; link; link = link->next) { Vec X = (Vec) link->vec; DM dmX; PetscSection section, globalSection, newSection = NULL; const char *name; PetscInt enforceDof = PETSC_DETERMINE; if ((link->ft != PETSC_VTK_POINT_FIELD) && (link->ft != PETSC_VTK_POINT_VECTOR_FIELD)) continue; if (link->ft == PETSC_VTK_POINT_VECTOR_FIELD) enforceDof = 3; ierr = PetscObjectGetName(link->vec, &name);CHKERRQ(ierr); ierr = VecGetDM(X, &dmX);CHKERRQ(ierr); if (dmX) { DMLabel subpointMap, subpointMapX; PetscInt dim, dimX, pStart, pEnd, qStart, qEnd; ierr = DMGetDefaultSection(dmX, §ion);CHKERRQ(ierr); /* Here is where we check whether dmX is a submesh of dm */ ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMGetDimension(dmX, &dimX);CHKERRQ(ierr); ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); ierr = DMPlexGetChart(dmX, &qStart, &qEnd);CHKERRQ(ierr); ierr = DMPlexGetSubpointMap(dm, &subpointMap);CHKERRQ(ierr); ierr = DMPlexGetSubpointMap(dmX, &subpointMapX);CHKERRQ(ierr); if (((dim != dimX) || ((pEnd-pStart) < (qEnd-qStart))) && subpointMap && !subpointMapX) { const PetscInt *ind = NULL; IS subpointIS; PetscInt n = 0, q; ierr = PetscSectionGetChart(section, &qStart, &qEnd);CHKERRQ(ierr); ierr = DMPlexCreateSubpointIS(dm, &subpointIS);CHKERRQ(ierr); if (subpointIS) { ierr = ISGetLocalSize(subpointIS, &n);CHKERRQ(ierr); ierr = ISGetIndices(subpointIS, &ind);CHKERRQ(ierr); } ierr = PetscSectionCreate(comm, &newSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(newSection, pStart, pEnd);CHKERRQ(ierr); for (q = qStart; q < qEnd; ++q) { PetscInt dof, off, p; ierr = PetscSectionGetDof(section, q, &dof);CHKERRQ(ierr); if (dof) { ierr = PetscFindInt(q, n, ind, &p);CHKERRQ(ierr); if (p >= pStart) { ierr = PetscSectionSetDof(newSection, p, dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, q, &off);CHKERRQ(ierr); ierr = PetscSectionSetOffset(newSection, p, off);CHKERRQ(ierr); } } } if (subpointIS) { ierr = ISRestoreIndices(subpointIS, &ind);CHKERRQ(ierr); ierr = ISDestroy(&subpointIS);CHKERRQ(ierr); } /* No need to setup section */ section = newSection; } } else { ierr = PetscObjectQuery(link->vec, "section", (PetscObject*) §ion);CHKERRQ(ierr); if (!section) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it", name); } if (!section) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it", name); ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); ierr = DMPlexVTKWriteField_ASCII(dm, section, globalSection, X, name, fp, enforceDof, PETSC_DETERMINE, 1.0);CHKERRQ(ierr); ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); if (newSection) {ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);} } } /* Cell Fields */ ierr = PetscOptionsGetBool(((PetscObject) dm)->prefix, "-dm_view_partition", &writePartition, NULL);CHKERRQ(ierr); if (hasCell || writePartition) { ierr = PetscFPrintf(comm, fp, "CELL_DATA %d\n", totCells);CHKERRQ(ierr); for (link = vtk->link; link; link = link->next) { Vec X = (Vec) link->vec; DM dmX; PetscSection section, globalSection; const char *name; PetscInt enforceDof = PETSC_DETERMINE; if ((link->ft != PETSC_VTK_CELL_FIELD) && (link->ft != PETSC_VTK_CELL_VECTOR_FIELD)) continue; if (link->ft == PETSC_VTK_CELL_VECTOR_FIELD) enforceDof = 3; ierr = PetscObjectGetName(link->vec, &name);CHKERRQ(ierr); ierr = VecGetDM(X, &dmX);CHKERRQ(ierr); if (dmX) { ierr = DMGetDefaultSection(dmX, §ion);CHKERRQ(ierr); } else { PetscContainer c; ierr = PetscObjectQuery(link->vec, "section", (PetscObject*) &c);CHKERRQ(ierr); if (!c) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it", name); ierr = PetscContainerGetPointer(c, (void**) §ion);CHKERRQ(ierr); } if (!section) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Vector %s had no PetscSection composed with it", name); ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); ierr = DMPlexVTKWriteField_ASCII(dm, section, globalSection, X, name, fp, enforceDof, PETSC_DETERMINE, 1.0);CHKERRQ(ierr); ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); } if (writePartition) { ierr = PetscFPrintf(comm, fp, "SCALARS partition int 1\n");CHKERRQ(ierr); ierr = PetscFPrintf(comm, fp, "LOOKUP_TABLE default\n");CHKERRQ(ierr); ierr = DMPlexVTKWritePartition_ASCII(dm, fp);CHKERRQ(ierr); } } /* Cleanup */ ierr = PetscSectionDestroy(&globalCoordSection);CHKERRQ(ierr); ierr = PetscLayoutDestroy(&vLayout);CHKERRQ(ierr); ierr = PetscFClose(comm, fp);CHKERRQ(ierr); PetscFunctionReturn(0); }
int main(int argc, char *argv[]) { PetscErrorCode ierr; DM dm; PetscBool interpolate = PETSC_TRUE; PetscInt dim; PetscInt pStart, pEnd; PetscInt vStart, vEnd; PetscInt eStart, eEnd; PetscInt cStart, cEnd; PetscSection s; ierr = PetscInitialize(&argc, &argv, (char*)0, help); CHKERRQ(ierr); ierr = DMPlexCreateGmshFromFile(MPI_COMM_WORLD, argv[1], interpolate, &dm); CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim); CHKERRQ(ierr); printf("dim = %d\n", dim); ierr = DMPlexGetChart(dm, &pStart, &pEnd); CHKERRQ(ierr); printf("chart: pstart, pend = %d %d\n", pStart, pEnd); // vertices ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd); CHKERRQ(ierr); printf("Depth 0: vstart, vend, len = %d %d %d\n", vStart, vEnd, vEnd-vStart); // edges ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd); CHKERRQ(ierr); printf("Depth 1: estart, eend, len = %d %d %d\n", eStart, eEnd, eEnd-eStart); // cells ierr = DMPlexGetDepthStratum(dm, 2, &cStart, &cEnd); CHKERRQ(ierr); printf("Depth 2: cstart, cend, len = %d %d %d\n", cStart, cEnd, cEnd-cStart); // cells adjacent to face { FILE * fid = fopen("face_nbr.txt","w"); for(PetscInt e=eStart; e<eEnd; ++e) { PetscInt nbr; ierr = DMPlexGetSupportSize(dm, e, &nbr); CHKERRQ(ierr); const PetscInt *nbcells; ierr = DMPlexGetSupport(dm, e, &nbcells); CHKERRQ(ierr); if(nbr == 1) // boundary face fprintf(fid, "%d %d\n",e-eStart+1,nbcells[0]-cStart+1); else if(nbr == 2) // interior face fprintf(fid, "%d %d %d\n",e-eStart+1,nbcells[0]-cStart+1,nbcells[1]-cStart+1); else { printf("nbr is not 1 or 2\n"); exit(0); } } fclose(fid); } // point coordinates { Vec coordinates; ierr = DMGetCoordinatesLocal(dm, &coordinates); CHKERRQ(ierr); const PetscScalar *coords; ierr = VecGetArrayRead(coordinates, &coords); CHKERRQ(ierr); DM dmCoord; ierr = DMGetCoordinateDM(dm, &dmCoord); CHKERRQ(ierr); FILE * fid = fopen("vertices.txt","w"); for(PetscInt v=vStart; v<vEnd; ++v) { PetscScalar *vertex; ierr = DMPlexPointLocalRead(dmCoord, v, coords, &vertex); CHKERRQ(ierr); fprintf(fid, "%f %f\n", vertex[0], vertex[1]); } fclose(fid); ierr = VecRestoreArrayRead(coordinates, &coords); CHKERRQ(ierr); } // compute cell and face geometry { Vec cellgeom, facegeom; ierr = DMPlexComputeGeometryFVM(dm, &cellgeom, &facegeom); CHKERRQ(ierr); // cell information DM dmCell; ierr = VecGetDM(cellgeom, &dmCell); CHKERRQ(ierr); const PetscScalar *cgeom; ierr = VecGetArrayRead(cellgeom, &cgeom); CHKERRQ(ierr); FILE * fid = fopen("cells.txt","w"); for(PetscInt c=cStart; c<cEnd; ++c) { // cell properties like volume, centroid PetscFVCellGeom *cg; ierr = DMPlexPointLocalRead(dmCell, c, cgeom, &cg); CHKERRQ(ierr); fprintf(fid, "%d %f %f %f\n", c-cStart+1, cg->volume, cg->centroid[0], cg->centroid[1]); } fclose(fid); ierr = VecRestoreArrayRead(cellgeom, &cgeom); CHKERRQ(ierr); // face information DM dmFace; ierr = VecGetDM(facegeom, &dmFace); CHKERRQ(ierr); const PetscScalar *fgeom; ierr = VecGetArrayRead(facegeom, &fgeom); CHKERRQ(ierr); fid = fopen("faces.txt","w"); for(PetscInt e=eStart; e<eEnd; ++e) { // face properties like area normal, centroid PetscFVFaceGeom *fg; ierr = DMPlexPointLocalRead(dmFace, e, fgeom, &fg); CHKERRQ(ierr); fprintf(fid, "%d %f %f %f %f\n", e-eStart+1, fg->normal[0], fg->normal[1], fg->centroid[0], fg->centroid[1]); } fclose(fid); ierr = VecRestoreArrayRead(facegeom, &fgeom); CHKERRQ(ierr); } // create section with one variable in each cell ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s); CHKERRQ(ierr); ierr = PetscSectionSetChart(s, pStart, pEnd); CHKERRQ(ierr); for(PetscInt c=cStart; c<cEnd; ++c) { ierr = PetscSectionSetDof(s, c, 1); CHKERRQ(ierr); } ierr = PetscSectionSetUp(s); CHKERRQ(ierr); // create vector to store solution Vec lv, gv; ierr = DMSetDefaultSection(dm, s); CHKERRQ(ierr); ierr = DMGetLocalVector(dm, &lv); CHKERRQ(ierr); ierr = DMGetGlobalVector(dm, &gv); CHKERRQ(ierr); }
/*@ DMPlexPermute - Reorder the mesh according to the input permutation Collective on DM Input Parameter: + dm - The DMPlex object - perm - The point permutation, perm[old point number] = new point number Output Parameter: . pdm - The permuted DM Level: intermediate .keywords: mesh .seealso: MatPermute() @*/ PetscErrorCode DMPlexPermute(DM dm, IS perm, DM *pdm) { DM_Plex *plex = (DM_Plex *) dm->data, *plexNew; PetscSection section, sectionNew; PetscInt dim; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(perm, IS_CLASSID, 2); PetscValidPointer(pdm, 3); ierr = DMCreate(PetscObjectComm((PetscObject) dm), pdm);CHKERRQ(ierr); ierr = DMSetType(*pdm, DMPLEX);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMSetDimension(*pdm, dim);CHKERRQ(ierr); ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); if (section) { ierr = PetscSectionPermute(section, perm, §ionNew);CHKERRQ(ierr); ierr = DMSetDefaultSection(*pdm, sectionNew);CHKERRQ(ierr); ierr = PetscSectionDestroy(§ionNew);CHKERRQ(ierr); } plexNew = (DM_Plex *) (*pdm)->data; /* Ignore ltogmap, ltogmapb */ /* Ignore sf, defaultSF */ /* Ignore globalVertexNumbers, globalCellNumbers */ /* Remap coordinates */ { DM cdm, cdmNew; PetscSection csection, csectionNew; Vec coordinates, coordinatesNew; PetscScalar *coords, *coordsNew; const PetscInt *pperm; PetscInt pStart, pEnd, p; const char *name; ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); ierr = DMGetDefaultSection(cdm, &csection);CHKERRQ(ierr); ierr = PetscSectionPermute(csection, perm, &csectionNew);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); ierr = VecDuplicate(coordinates, &coordinatesNew);CHKERRQ(ierr); ierr = PetscObjectGetName((PetscObject)coordinates,&name);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject)coordinatesNew,name);CHKERRQ(ierr); ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr); ierr = PetscSectionGetChart(csectionNew, &pStart, &pEnd);CHKERRQ(ierr); ierr = ISGetIndices(perm, &pperm);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; ierr = PetscSectionGetDof(csectionNew, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(csection, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(csectionNew, pperm[p], &offNew);CHKERRQ(ierr); for (d = 0; d < dof; ++d) coordsNew[offNew+d] = coords[off+d]; } ierr = ISRestoreIndices(perm, &pperm);CHKERRQ(ierr); ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr); ierr = DMGetCoordinateDM(*pdm, &cdmNew);CHKERRQ(ierr); ierr = DMSetDefaultSection(cdmNew, csectionNew);CHKERRQ(ierr); ierr = DMSetCoordinatesLocal(*pdm, coordinatesNew);CHKERRQ(ierr); ierr = PetscSectionDestroy(&csectionNew);CHKERRQ(ierr); ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr); } /* Reorder labels */ { PetscInt numLabels, l; DMLabel label, labelNew; ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); for (l = numLabels-1; l >= 0; --l) { ierr = DMGetLabelByNum(dm, l, &label);CHKERRQ(ierr); ierr = DMLabelPermute(label, perm, &labelNew);CHKERRQ(ierr); ierr = DMAddLabel(*pdm, labelNew);CHKERRQ(ierr); } if (plex->subpointMap) {ierr = DMLabelPermute(plex->subpointMap, perm, &plexNew->subpointMap);CHKERRQ(ierr);} } /* Reorder topology */ { const PetscInt *pperm; PetscInt maxConeSize, maxSupportSize, n, pStart, pEnd, p; ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); plexNew->maxConeSize = maxConeSize; plexNew->maxSupportSize = maxSupportSize; ierr = PetscSectionDestroy(&plexNew->coneSection);CHKERRQ(ierr); ierr = PetscSectionPermute(plex->coneSection, perm, &plexNew->coneSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(plexNew->coneSection, &n);CHKERRQ(ierr); ierr = PetscMalloc1(n, &plexNew->cones);CHKERRQ(ierr); ierr = PetscMalloc1(n, &plexNew->coneOrientations);CHKERRQ(ierr); ierr = ISGetIndices(perm, &pperm);CHKERRQ(ierr); ierr = PetscSectionGetChart(plex->coneSection, &pStart, &pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; ierr = PetscSectionGetDof(plexNew->coneSection, pperm[p], &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(plex->coneSection, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(plexNew->coneSection, pperm[p], &offNew);CHKERRQ(ierr); for (d = 0; d < dof; ++d) { plexNew->cones[offNew+d] = pperm[plex->cones[off+d]]; plexNew->coneOrientations[offNew+d] = plex->coneOrientations[off+d]; } } ierr = PetscSectionDestroy(&plexNew->supportSection);CHKERRQ(ierr); ierr = PetscSectionPermute(plex->supportSection, perm, &plexNew->supportSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(plexNew->supportSection, &n);CHKERRQ(ierr); ierr = PetscMalloc1(n, &plexNew->supports);CHKERRQ(ierr); ierr = PetscSectionGetChart(plex->supportSection, &pStart, &pEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, off, offNew, d; ierr = PetscSectionGetDof(plexNew->supportSection, pperm[p], &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(plex->supportSection, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(plexNew->supportSection, pperm[p], &offNew);CHKERRQ(ierr); for (d = 0; d < dof; ++d) { plexNew->supports[offNew+d] = pperm[plex->supports[off+d]]; } } ierr = ISRestoreIndices(perm, &pperm);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/*@ PetscConvEstGetConvRate - Returns an estimate of the convergence rate for the discretization Not collective Input Parameter: . ce - The PetscConvEst object Output Parameter: . alpha - The convergence rate for each field Note: The convergence rate alpha is defined by $ || u_h - u_exact || < C h^alpha where u_h is the discrete solution, and h is a measure of the discretization size. We solve a series of problems on refined meshes, calculate an error based upon the exact solution in the DS, and then fit the result to our model above using linear regression. Options database keys: . -snes_convergence_estimate : Execute convergence estimation and print out the rate Level: intermediate .keywords: PetscConvEst, convergence .seealso: PetscConvEstSetSolver(), PetscConvEstCreate(), PetscConvEstGetConvRate() @*/ PetscErrorCode PetscConvEstGetConvRate(PetscConvEst ce, PetscReal alpha[]) { DM *dm; PetscObject disc; MPI_Comm comm; const char *uname, *dmname; void *ctx; Vec u; PetscReal t = 0.0, *x, *y, slope, intercept; PetscInt *dof, dim, Nr = ce->Nr, r, f, oldlevel, oldnlev; PetscLogEvent event; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject) ce, &comm);CHKERRQ(ierr); ierr = DMGetDimension(ce->idm, &dim);CHKERRQ(ierr); ierr = DMGetApplicationContext(ce->idm, &ctx);CHKERRQ(ierr); ierr = DMPlexSetRefinementUniform(ce->idm, PETSC_TRUE);CHKERRQ(ierr); ierr = DMGetRefineLevel(ce->idm, &oldlevel);CHKERRQ(ierr); ierr = PetscMalloc2((Nr+1), &dm, (Nr+1)*ce->Nf, &dof);CHKERRQ(ierr); dm[0] = ce->idm; for (f = 0; f < ce->Nf; ++f) alpha[f] = 0.0; /* Loop over meshes */ ierr = PetscLogEventRegister("ConvEst Error", PETSC_OBJECT_CLASSID, &event);CHKERRQ(ierr); for (r = 0; r <= Nr; ++r) { PetscLogStage stage; char stageName[PETSC_MAX_PATH_LEN]; ierr = PetscSNPrintf(stageName, PETSC_MAX_PATH_LEN-1, "ConvEst Refinement Level %D", r);CHKERRQ(ierr); ierr = PetscLogStageRegister(stageName, &stage);CHKERRQ(ierr); ierr = PetscLogStagePush(stage);CHKERRQ(ierr); if (r > 0) { ierr = DMRefine(dm[r-1], MPI_COMM_NULL, &dm[r]);CHKERRQ(ierr); ierr = DMSetCoarseDM(dm[r], dm[r-1]);CHKERRQ(ierr); ierr = DMCopyDisc(ce->idm, dm[r]);CHKERRQ(ierr); ierr = DMCopyTransform(ce->idm, dm[r]);CHKERRQ(ierr); ierr = PetscObjectGetName((PetscObject) dm[r-1], &dmname);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) dm[r], dmname);CHKERRQ(ierr); for (f = 0; f <= ce->Nf; ++f) { PetscErrorCode (*nspconstr)(DM, PetscInt, MatNullSpace *); ierr = DMGetNullSpaceConstructor(dm[r-1], f, &nspconstr);CHKERRQ(ierr); ierr = DMSetNullSpaceConstructor(dm[r], f, nspconstr);CHKERRQ(ierr); } } ierr = DMViewFromOptions(dm[r], NULL, "-conv_dm_view");CHKERRQ(ierr); /* Create solution */ ierr = DMCreateGlobalVector(dm[r], &u);CHKERRQ(ierr); ierr = DMGetField(dm[r], 0, NULL, &disc);CHKERRQ(ierr); ierr = PetscObjectGetName(disc, &uname);CHKERRQ(ierr); ierr = PetscObjectSetName((PetscObject) u, uname);CHKERRQ(ierr); /* Setup solver */ ierr = SNESReset(ce->snes);CHKERRQ(ierr); ierr = SNESSetDM(ce->snes, dm[r]);CHKERRQ(ierr); ierr = DMPlexSetSNESLocalFEM(dm[r], ctx, ctx, ctx);CHKERRQ(ierr); ierr = SNESSetFromOptions(ce->snes);CHKERRQ(ierr); /* Create initial guess */ ierr = DMProjectFunction(dm[r], t, ce->initGuess, ce->ctxs, INSERT_VALUES, u);CHKERRQ(ierr); ierr = SNESSolve(ce->snes, NULL, u);CHKERRQ(ierr); ierr = PetscLogEventBegin(event, ce, 0, 0, 0);CHKERRQ(ierr); ierr = DMComputeL2FieldDiff(dm[r], t, ce->exactSol, ce->ctxs, u, &ce->errors[r*ce->Nf]);CHKERRQ(ierr); ierr = PetscLogEventEnd(event, ce, 0, 0, 0);CHKERRQ(ierr); for (f = 0; f < ce->Nf; ++f) { PetscSection s, fs; PetscInt lsize; /* Could use DMGetOutputDM() to add in Dirichlet dofs */ ierr = DMGetSection(dm[r], &s);CHKERRQ(ierr); ierr = PetscSectionGetField(s, f, &fs);CHKERRQ(ierr); ierr = PetscSectionGetConstrainedStorageSize(fs, &lsize);CHKERRQ(ierr); ierr = MPI_Allreduce(&lsize, &dof[r*ce->Nf+f], 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) ce->snes));CHKERRQ(ierr); ierr = PetscLogEventSetDof(event, f, dof[r*ce->Nf+f]);CHKERRQ(ierr); ierr = PetscLogEventSetError(event, f, ce->errors[r*ce->Nf+f]);CHKERRQ(ierr); } /* Monitor */ if (ce->monitor) { PetscReal *errors = &ce->errors[r*ce->Nf]; ierr = PetscPrintf(comm, "L_2 Error: ");CHKERRQ(ierr); if (ce->Nf > 1) {ierr = PetscPrintf(comm, "[");CHKERRQ(ierr);} for (f = 0; f < ce->Nf; ++f) { if (f > 0) {ierr = PetscPrintf(comm, ", ");CHKERRQ(ierr);} if (errors[f] < 1.0e-11) {ierr = PetscPrintf(comm, "< 1e-11");CHKERRQ(ierr);} else {ierr = PetscPrintf(comm, "%g", (double)errors[f]);CHKERRQ(ierr);} } if (ce->Nf > 1) {ierr = PetscPrintf(comm, "]");CHKERRQ(ierr);} ierr = PetscPrintf(comm, "\n");CHKERRQ(ierr); } if (!r) { /* PCReset() does not wipe out the level structure */ KSP ksp; PC pc; ierr = SNESGetKSP(ce->snes, &ksp);CHKERRQ(ierr); ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr); ierr = PCMGGetLevels(pc, &oldnlev);CHKERRQ(ierr); } /* Cleanup */ ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = PetscLogStagePop();CHKERRQ(ierr); } for (r = 1; r <= Nr; ++r) { ierr = DMDestroy(&dm[r]);CHKERRQ(ierr); } /* Fit convergence rate */ ierr = PetscMalloc2(Nr+1, &x, Nr+1, &y);CHKERRQ(ierr); for (f = 0; f < ce->Nf; ++f) { for (r = 0; r <= Nr; ++r) { x[r] = PetscLog10Real(dof[r*ce->Nf+f]); y[r] = PetscLog10Real(ce->errors[r*ce->Nf+f]); } ierr = PetscLinearRegression(Nr+1, x, y, &slope, &intercept);CHKERRQ(ierr); /* Since h^{-dim} = N, lg err = s lg N + b = -s dim lg h + b */ alpha[f] = -slope * dim; } ierr = PetscFree2(x, y);CHKERRQ(ierr); ierr = PetscFree2(dm, dof);CHKERRQ(ierr); /* Restore solver */ ierr = SNESReset(ce->snes);CHKERRQ(ierr); { /* PCReset() does not wipe out the level structure */ KSP ksp; PC pc; ierr = SNESGetKSP(ce->snes, &ksp);CHKERRQ(ierr); ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr); ierr = PCMGSetLevels(pc, oldnlev, NULL);CHKERRQ(ierr); ierr = DMSetRefineLevel(ce->idm, oldlevel);CHKERRQ(ierr); /* The damn DMCoarsen() calls in PCMG can reset this */ } ierr = SNESSetDM(ce->snes, ce->idm);CHKERRQ(ierr); ierr = DMPlexSetSNESLocalFEM(ce->idm, ctx, ctx, ctx);CHKERRQ(ierr); ierr = SNESSetFromOptions(ce->snes);CHKERRQ(ierr); PetscFunctionReturn(0); }