1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 13 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices() 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: VecViewFromOptions(), VecView() 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 PetscCheckFalse(numVals % Nc,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3]; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheckFalse(dim != 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %D", dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %D", dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %D", dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n", name)); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n", name)); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheckFalse(Nf != 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %D", Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %D fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %D components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4D) dim %2D offset %3D", p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1); 929 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 930 PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1); 931 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 932 if (!useLabels) numLabels = 0; 933 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 934 if (!useColors) { 935 numColors = 3; 936 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 937 } 938 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 939 if (!useColors) { 940 numLColors = 4; 941 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 942 } 943 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 944 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 945 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 946 PetscCheckFalse(flg && plotEdges && depth < dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p > 0 && p == size-1) { 993 PetscCall(PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p)); 994 } else if (p > 0) { 995 PetscCall(PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p)); 996 } 997 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p)); 998 } 999 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1000 } 1001 if (drawHasse) { 1002 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1003 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%D}\n", vStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%D}\n", vEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%D}\n", vEnd-vStart)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%D}\n", eStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%D}\n", eEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%D}\n", eEnd-eStart)); 1012 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%D}\n", cStart)); 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%D}\n", cEnd-1)); 1014 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%D}\n", cEnd-cStart)); 1015 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1016 } 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1018 1019 /* Plot vertices */ 1020 PetscCall(VecGetArray(coordinates, &coords)); 1021 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1022 for (v = vStart; v < vEnd; ++v) { 1023 PetscInt off, dof, d; 1024 PetscBool isLabeled = PETSC_FALSE; 1025 1026 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1027 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1028 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1029 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1030 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof); 1031 for (d = 0; d < dof; ++d) { 1032 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1033 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1034 } 1035 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1036 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1037 for (d = 0; d < dof; ++d) { 1038 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1039 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1040 } 1041 if (drawHasse) color = colors[0%numColors]; 1042 else color = colors[rank%numColors]; 1043 for (l = 0; l < numLabels; ++l) { 1044 PetscInt val; 1045 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1046 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1047 } 1048 if (drawNumbers[0]) { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v)); 1050 } else if (drawColors[0]) { 1051 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1052 } else { 1053 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", v, rank)); 1054 } 1055 } 1056 PetscCall(VecRestoreArray(coordinates, &coords)); 1057 PetscCall(PetscViewerFlush(viewer)); 1058 /* Plot edges */ 1059 if (plotEdges) { 1060 PetscCall(VecGetArray(coordinates, &coords)); 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1062 for (e = eStart; e < eEnd; ++e) { 1063 const PetscInt *cone; 1064 PetscInt coneSize, offA, offB, dof, d; 1065 1066 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1067 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1068 PetscCheckFalse(coneSize != 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize); 1069 PetscCall(DMPlexGetCone(dm, e, &cone)); 1070 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1071 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1072 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1073 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1074 for (d = 0; d < dof; ++d) { 1075 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1076 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1077 } 1078 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1079 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1080 for (d = 0; d < dof; ++d) { 1081 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1082 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1083 } 1084 if (drawHasse) color = colors[1%numColors]; 1085 else color = colors[rank%numColors]; 1086 for (l = 0; l < numLabels; ++l) { 1087 PetscInt val; 1088 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1089 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1090 } 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e)); 1092 } 1093 PetscCall(VecRestoreArray(coordinates, &coords)); 1094 PetscCall(PetscViewerFlush(viewer)); 1095 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1096 } 1097 /* Plot cells */ 1098 if (dim == 3 || !drawNumbers[1]) { 1099 for (e = eStart; e < eEnd; ++e) { 1100 const PetscInt *cone; 1101 1102 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1103 color = colors[rank%numColors]; 1104 for (l = 0; l < numLabels; ++l) { 1105 PetscInt val; 1106 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1107 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1108 } 1109 PetscCall(DMPlexGetCone(dm, e, &cone)); 1110 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank)); 1111 } 1112 } else { 1113 DMPolytopeType ct; 1114 1115 /* Drawing a 2D polygon */ 1116 for (c = cStart; c < cEnd; ++c) { 1117 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1118 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1119 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1120 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1121 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1122 const PetscInt *cone; 1123 PetscInt coneSize, e; 1124 1125 PetscCall(DMPlexGetCone(dm, c, &cone)); 1126 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1127 for (e = 0; e < coneSize; ++e) { 1128 const PetscInt *econe; 1129 1130 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1131 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d) -- (%D_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1132 } 1133 } else { 1134 PetscInt *closure = NULL; 1135 PetscInt closureSize, Nv = 0, v; 1136 1137 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1138 for (p = 0; p < closureSize*2; p += 2) { 1139 const PetscInt point = closure[p]; 1140 1141 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1142 } 1143 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1144 for (v = 0; v <= Nv; ++v) { 1145 const PetscInt vertex = closure[v%Nv]; 1146 1147 if (v > 0) { 1148 if (plotEdges) { 1149 const PetscInt *edge; 1150 PetscInt endpoints[2], ne; 1151 1152 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1153 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1154 PetscCheckFalse(ne != 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %D, %D", endpoints[0], endpoints[1]); 1155 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d) -- ", edge[0], rank)); 1156 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1157 } else { 1158 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1159 } 1160 } 1161 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", vertex, rank)); 1162 } 1163 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1164 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 } 1166 } 1167 } 1168 PetscCall(VecGetArray(coordinates, &coords)); 1169 for (c = cStart; c < cEnd; ++c) { 1170 double ccoords[3] = {0.0, 0.0, 0.0}; 1171 PetscBool isLabeled = PETSC_FALSE; 1172 PetscInt *closure = NULL; 1173 PetscInt closureSize, dof, d, n = 0; 1174 1175 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1176 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1177 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1178 for (p = 0; p < closureSize*2; p += 2) { 1179 const PetscInt point = closure[p]; 1180 PetscInt off; 1181 1182 if ((point < vStart) || (point >= vEnd)) continue; 1183 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1184 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1185 for (d = 0; d < dof; ++d) { 1186 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1187 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1188 } 1189 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1190 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1191 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1192 ++n; 1193 } 1194 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1195 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1196 for (d = 0; d < dof; ++d) { 1197 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1198 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1199 } 1200 if (drawHasse) color = colors[depth%numColors]; 1201 else color = colors[rank%numColors]; 1202 for (l = 0; l < numLabels; ++l) { 1203 PetscInt val; 1204 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1205 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1206 } 1207 if (drawNumbers[dim]) { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c)); 1209 } else if (drawColors[dim]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1211 } else { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", c, rank)); 1213 } 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 if (drawHasse) { 1217 color = colors[depth%numColors]; 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1221 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1223 1224 color = colors[1%numColors]; 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1226 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1227 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1228 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1230 1231 color = colors[0%numColors]; 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1235 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1237 1238 for (p = pStart; p < pEnd; ++p) { 1239 const PetscInt *cone; 1240 PetscInt coneSize, cp; 1241 1242 PetscCall(DMPlexGetCone(dm, p, &cone)); 1243 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1244 for (cp = 0; cp < coneSize; ++cp) { 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%D_%d) -- (%D_%d);\n", cone[cp], rank, p, rank)); 1246 } 1247 } 1248 } 1249 PetscCall(PetscViewerFlush(viewer)); 1250 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name)); 1253 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1254 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1255 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1256 PetscCall(PetscFree3(names, colors, lcolors)); 1257 PetscCall(PetscBTDestroy(&wp)); 1258 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1259 Vec cown,acown; 1260 VecScatter sct; 1261 ISLocalToGlobalMapping g2l; 1262 IS gid,acis; 1263 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1264 MPI_Group ggroup,ngroup; 1265 PetscScalar *array,nid; 1266 const PetscInt *idxs; 1267 PetscInt *idxs2,*start,*adjacency,*work; 1268 PetscInt64 lm[3],gm[3]; 1269 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1270 PetscMPIInt d1,d2,rank; 1271 1272 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1273 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1274 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1275 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1276 #endif 1277 if (ncomm != MPI_COMM_NULL) { 1278 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1279 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1280 d1 = 0; 1281 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1282 nid = d2; 1283 PetscCallMPI(MPI_Group_free(&ggroup)); 1284 PetscCallMPI(MPI_Group_free(&ngroup)); 1285 PetscCallMPI(MPI_Comm_free(&ncomm)); 1286 } else nid = 0.0; 1287 1288 /* Get connectivity */ 1289 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1290 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1291 1292 /* filter overlapped local cells */ 1293 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1294 PetscCall(ISGetIndices(gid,&idxs)); 1295 PetscCall(ISGetLocalSize(gid,&cum)); 1296 PetscCall(PetscMalloc1(cum,&idxs2)); 1297 for (c = cStart, cum = 0; c < cEnd; c++) { 1298 if (idxs[c-cStart] < 0) continue; 1299 idxs2[cum++] = idxs[c-cStart]; 1300 } 1301 PetscCall(ISRestoreIndices(gid,&idxs)); 1302 PetscCheckFalse(numVertices != cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum); 1303 PetscCall(ISDestroy(&gid)); 1304 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1305 1306 /* support for node-aware cell locality */ 1307 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1308 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1309 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1310 PetscCall(VecGetArray(cown,&array)); 1311 for (c = 0; c < numVertices; c++) array[c] = nid; 1312 PetscCall(VecRestoreArray(cown,&array)); 1313 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1314 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1315 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1316 PetscCall(ISDestroy(&acis)); 1317 PetscCall(VecScatterDestroy(&sct)); 1318 PetscCall(VecDestroy(&cown)); 1319 1320 /* compute edgeCut */ 1321 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1322 PetscCall(PetscMalloc1(cum,&work)); 1323 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1324 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1325 PetscCall(ISDestroy(&gid)); 1326 PetscCall(VecGetArray(acown,&array)); 1327 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1328 PetscInt totl; 1329 1330 totl = start[c+1]-start[c]; 1331 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1332 for (i = 0; i < totl; i++) { 1333 if (work[i] < 0) { 1334 ect += 1; 1335 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1336 } 1337 } 1338 } 1339 PetscCall(PetscFree(work)); 1340 PetscCall(VecRestoreArray(acown,&array)); 1341 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1342 lm[1] = -numVertices; 1343 PetscCallMPI(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1344 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1345 lm[0] = ect; /* edgeCut */ 1346 lm[1] = ectn; /* node-aware edgeCut */ 1347 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1348 PetscCallMPI(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1349 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2])); 1350 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1351 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1352 #else 1353 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1354 #endif 1355 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1356 PetscCall(PetscFree(start)); 1357 PetscCall(PetscFree(adjacency)); 1358 PetscCall(VecDestroy(&acown)); 1359 } else { 1360 const char *name; 1361 PetscInt *sizes, *hybsizes, *ghostsizes; 1362 PetscInt locDepth, depth, cellHeight, dim, d; 1363 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1364 PetscInt numLabels, l, maxSize = 17; 1365 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1366 MPI_Comm comm; 1367 PetscMPIInt size, rank; 1368 1369 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1370 PetscCallMPI(MPI_Comm_size(comm, &size)); 1371 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1372 PetscCall(DMGetDimension(dm, &dim)); 1373 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1374 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1375 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1376 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s")); 1377 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight)); 1378 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1379 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1380 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1381 gcNum = gcEnd - gcStart; 1382 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1383 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1384 for (d = 0; d <= depth; d++) { 1385 PetscInt Nc[2] = {0, 0}, ict; 1386 1387 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1388 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1389 ict = ct0; 1390 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1391 ct0 = (DMPolytopeType) ict; 1392 for (p = pStart; p < pEnd; ++p) { 1393 DMPolytopeType ct; 1394 1395 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1396 if (ct == ct0) ++Nc[0]; 1397 else ++Nc[1]; 1398 } 1399 if (size < maxSize) { 1400 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1401 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1402 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %D-cells per rank:", (depth == 1) && d ? dim : d)); 1404 for (p = 0; p < size; ++p) { 1405 if (rank == 0) { 1406 PetscCall(PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p])); 1407 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p])); 1408 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p])); 1409 } 1410 } 1411 } else { 1412 PetscInt locMinMax[2]; 1413 1414 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1415 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1416 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1417 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1418 if (d == depth) { 1419 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1420 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1421 } 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %D-cells per rank:", (depth == 1) && d ? dim : d)); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1424 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1425 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1426 } 1427 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1428 } 1429 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1430 { 1431 const PetscReal *maxCell; 1432 const PetscReal *L; 1433 const DMBoundaryType *bd; 1434 PetscBool per, localized; 1435 1436 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1437 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1438 if (per) { 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1440 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1441 for (d = 0; d < dim; ++d) { 1442 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1443 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1444 } 1445 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1446 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1447 } 1448 } 1449 PetscCall(DMGetNumLabels(dm, &numLabels)); 1450 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1451 for (l = 0; l < numLabels; ++l) { 1452 DMLabel label; 1453 const char *name; 1454 IS valueIS; 1455 const PetscInt *values; 1456 PetscInt numValues, v; 1457 1458 PetscCall(DMGetLabelName(dm, l, &name)); 1459 PetscCall(DMGetLabel(dm, name, &label)); 1460 PetscCall(DMLabelGetNumValues(label, &numValues)); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues)); 1462 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1463 PetscCall(ISGetIndices(valueIS, &values)); 1464 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1465 for (v = 0; v < numValues; ++v) { 1466 PetscInt size; 1467 1468 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1469 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1470 PetscCall(PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size)); 1471 } 1472 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1473 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1474 PetscCall(ISRestoreIndices(valueIS, &values)); 1475 PetscCall(ISDestroy(&valueIS)); 1476 } 1477 { 1478 char **labelNames; 1479 PetscInt Nl = numLabels; 1480 PetscBool flg; 1481 1482 PetscCall(PetscMalloc1(Nl, &labelNames)); 1483 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1484 for (l = 0; l < Nl; ++l) { 1485 DMLabel label; 1486 1487 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1488 if (flg) { 1489 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1490 PetscCall(DMLabelView(label, viewer)); 1491 } 1492 PetscCall(PetscFree(labelNames[l])); 1493 } 1494 PetscCall(PetscFree(labelNames)); 1495 } 1496 /* If no fields are specified, people do not want to see adjacency */ 1497 if (dm->Nf) { 1498 PetscInt f; 1499 1500 for (f = 0; f < dm->Nf; ++f) { 1501 const char *name; 1502 1503 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1504 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1505 PetscCall(PetscViewerASCIIPushTab(viewer)); 1506 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1507 if (dm->fields[f].adjacency[0]) { 1508 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1509 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1510 } else { 1511 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1512 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1513 } 1514 PetscCall(PetscViewerASCIIPopTab(viewer)); 1515 } 1516 } 1517 PetscCall(DMGetCoarseDM(dm, &cdm)); 1518 if (cdm) { 1519 PetscCall(PetscViewerASCIIPushTab(viewer)); 1520 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1521 PetscCall(PetscViewerASCIIPopTab(viewer)); 1522 } 1523 } 1524 PetscFunctionReturn(0); 1525 } 1526 1527 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1528 { 1529 DMPolytopeType ct; 1530 PetscMPIInt rank; 1531 PetscInt cdim; 1532 1533 PetscFunctionBegin; 1534 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1535 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1536 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1537 switch (ct) { 1538 case DM_POLYTOPE_SEGMENT: 1539 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1540 switch (cdim) { 1541 case 1: 1542 { 1543 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1544 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1545 1546 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1547 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1548 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1549 } 1550 break; 1551 case 2: 1552 { 1553 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1554 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1555 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1556 1557 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1558 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1559 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1560 } 1561 break; 1562 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %D", cdim); 1563 } 1564 break; 1565 case DM_POLYTOPE_TRIANGLE: 1566 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1567 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1568 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1569 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1570 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1571 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1572 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1573 break; 1574 case DM_POLYTOPE_QUADRILATERAL: 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1580 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1581 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1582 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1583 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1587 break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1589 } 1590 PetscFunctionReturn(0); 1591 } 1592 1593 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1594 { 1595 DMPolytopeType ct; 1596 PetscReal centroid[2] = {0., 0.}; 1597 PetscMPIInt rank; 1598 PetscInt fillColor, v, e, d; 1599 1600 PetscFunctionBegin; 1601 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1602 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1603 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1604 switch (ct) { 1605 case DM_POLYTOPE_TRIANGLE: 1606 { 1607 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1608 1609 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1610 for (e = 0; e < 3; ++e) { 1611 refCoords[0] = refVertices[e*2+0]; 1612 refCoords[1] = refVertices[e*2+1]; 1613 for (d = 1; d <= edgeDiv; ++d) { 1614 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1615 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1616 } 1617 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1618 for (d = 0; d < edgeDiv; ++d) { 1619 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1620 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1621 } 1622 } 1623 } 1624 break; 1625 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1626 } 1627 PetscFunctionReturn(0); 1628 } 1629 1630 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1631 { 1632 PetscDraw draw; 1633 DM cdm; 1634 PetscSection coordSection; 1635 Vec coordinates; 1636 const PetscScalar *coords; 1637 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1638 PetscReal *refCoords, *edgeCoords; 1639 PetscBool isnull, drawAffine = PETSC_TRUE; 1640 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1641 1642 PetscFunctionBegin; 1643 PetscCall(DMGetCoordinateDim(dm, &dim)); 1644 PetscCheckFalse(dim > 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 1645 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1646 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1647 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1648 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1649 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1650 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1651 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1652 1653 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1654 PetscCall(PetscDrawIsNull(draw, &isnull)); 1655 if (isnull) PetscFunctionReturn(0); 1656 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1657 1658 PetscCall(VecGetLocalSize(coordinates, &N)); 1659 PetscCall(VecGetArrayRead(coordinates, &coords)); 1660 for (c = 0; c < N; c += dim) { 1661 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1662 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1663 } 1664 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1665 PetscCallMPI(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1666 PetscCallMPI(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1667 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1668 PetscCall(PetscDrawClear(draw)); 1669 1670 for (c = cStart; c < cEnd; ++c) { 1671 PetscScalar *coords = NULL; 1672 PetscInt numCoords; 1673 1674 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1675 if (drawAffine) { 1676 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1677 } else { 1678 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1679 } 1680 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1681 } 1682 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1683 PetscCall(PetscDrawFlush(draw)); 1684 PetscCall(PetscDrawPause(draw)); 1685 PetscCall(PetscDrawSave(draw)); 1686 PetscFunctionReturn(0); 1687 } 1688 1689 #if defined(PETSC_HAVE_EXODUSII) 1690 #include <exodusII.h> 1691 #include <petscviewerexodusii.h> 1692 #endif 1693 1694 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1695 { 1696 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1697 char name[PETSC_MAX_PATH_LEN]; 1698 1699 PetscFunctionBegin; 1700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1701 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1704 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1705 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1706 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1707 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1708 if (iascii) { 1709 PetscViewerFormat format; 1710 PetscCall(PetscViewerGetFormat(viewer, &format)); 1711 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1712 PetscCall(DMPlexView_GLVis(dm, viewer)); 1713 } else { 1714 PetscCall(DMPlexView_Ascii(dm, viewer)); 1715 } 1716 } else if (ishdf5) { 1717 #if defined(PETSC_HAVE_HDF5) 1718 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1719 #else 1720 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1721 #endif 1722 } else if (isvtk) { 1723 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1724 } else if (isdraw) { 1725 PetscCall(DMPlexView_Draw(dm, viewer)); 1726 } else if (isglvis) { 1727 PetscCall(DMPlexView_GLVis(dm, viewer)); 1728 #if defined(PETSC_HAVE_EXODUSII) 1729 } else if (isexodus) { 1730 /* 1731 exodusII requires that all sets be part of exactly one cell set. 1732 If the dm does not have a "Cell Sets" label defined, we create one 1733 with ID 1, containig all cells. 1734 Note that if the Cell Sets label is defined but does not cover all cells, 1735 we may still have a problem. This should probably be checked here or in the viewer; 1736 */ 1737 PetscInt numCS; 1738 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1739 if (!numCS) { 1740 PetscInt cStart, cEnd, c; 1741 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1742 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1743 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1744 } 1745 PetscCall(DMView_PlexExodusII(dm, viewer)); 1746 #endif 1747 } else { 1748 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1749 } 1750 /* Optionally view the partition */ 1751 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1752 if (flg) { 1753 Vec ranks; 1754 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1755 PetscCall(VecView(ranks, viewer)); 1756 PetscCall(VecDestroy(&ranks)); 1757 } 1758 /* Optionally view a label */ 1759 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1760 if (flg) { 1761 DMLabel label; 1762 Vec val; 1763 1764 PetscCall(DMGetLabel(dm, name, &label)); 1765 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1766 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1767 PetscCall(VecView(val, viewer)); 1768 PetscCall(VecDestroy(&val)); 1769 } 1770 PetscFunctionReturn(0); 1771 } 1772 1773 /*@ 1774 DMPlexTopologyView - Saves a DMPlex topology into a file 1775 1776 Collective on DM 1777 1778 Input Parameters: 1779 + dm - The DM whose topology is to be saved 1780 - viewer - The PetscViewer for saving 1781 1782 Level: advanced 1783 1784 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad() 1785 @*/ 1786 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1787 { 1788 PetscBool ishdf5; 1789 1790 PetscFunctionBegin; 1791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1792 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1793 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1794 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1795 if (ishdf5) { 1796 #if defined(PETSC_HAVE_HDF5) 1797 PetscViewerFormat format; 1798 PetscCall(PetscViewerGetFormat(viewer, &format)); 1799 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1800 IS globalPointNumbering; 1801 1802 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1803 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1804 PetscCall(ISDestroy(&globalPointNumbering)); 1805 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1806 #else 1807 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1808 #endif 1809 } 1810 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1811 PetscFunctionReturn(0); 1812 } 1813 1814 /*@ 1815 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1816 1817 Collective on DM 1818 1819 Input Parameters: 1820 + dm - The DM whose coordinates are to be saved 1821 - viewer - The PetscViewer for saving 1822 1823 Level: advanced 1824 1825 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad() 1826 @*/ 1827 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1828 { 1829 PetscBool ishdf5; 1830 1831 PetscFunctionBegin; 1832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1833 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1834 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1835 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1836 if (ishdf5) { 1837 #if defined(PETSC_HAVE_HDF5) 1838 PetscViewerFormat format; 1839 PetscCall(PetscViewerGetFormat(viewer, &format)); 1840 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1841 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1842 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1843 #else 1844 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1845 #endif 1846 } 1847 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1848 PetscFunctionReturn(0); 1849 } 1850 1851 /*@ 1852 DMPlexLabelsView - Saves DMPlex labels into a file 1853 1854 Collective on DM 1855 1856 Input Parameters: 1857 + dm - The DM whose labels are to be saved 1858 - viewer - The PetscViewer for saving 1859 1860 Level: advanced 1861 1862 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad() 1863 @*/ 1864 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1865 { 1866 PetscBool ishdf5; 1867 1868 PetscFunctionBegin; 1869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1870 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1871 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1872 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1873 if (ishdf5) { 1874 #if defined(PETSC_HAVE_HDF5) 1875 IS globalPointNumbering; 1876 PetscViewerFormat format; 1877 1878 PetscCall(PetscViewerGetFormat(viewer, &format)); 1879 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1880 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1881 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1882 PetscCall(ISDestroy(&globalPointNumbering)); 1883 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1884 #else 1885 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1886 #endif 1887 } 1888 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1889 PetscFunctionReturn(0); 1890 } 1891 1892 /*@ 1893 DMPlexSectionView - Saves a section associated with a DMPlex 1894 1895 Collective on DM 1896 1897 Input Parameters: 1898 + dm - The DM that contains the topology on which the section to be saved is defined 1899 . viewer - The PetscViewer for saving 1900 - sectiondm - The DM that contains the section to be saved 1901 1902 Level: advanced 1903 1904 Notes: 1905 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1906 1907 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1908 1909 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad() 1910 @*/ 1911 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1912 { 1913 PetscBool ishdf5; 1914 1915 PetscFunctionBegin; 1916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1917 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1918 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1919 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1920 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1921 if (ishdf5) { 1922 #if defined(PETSC_HAVE_HDF5) 1923 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1924 #else 1925 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1926 #endif 1927 } 1928 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1929 PetscFunctionReturn(0); 1930 } 1931 1932 /*@ 1933 DMPlexGlobalVectorView - Saves a global vector 1934 1935 Collective on DM 1936 1937 Input Parameters: 1938 + dm - The DM that represents the topology 1939 . viewer - The PetscViewer to save data with 1940 . sectiondm - The DM that contains the global section on which vec is defined 1941 - vec - The global vector to be saved 1942 1943 Level: advanced 1944 1945 Notes: 1946 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1947 1948 Typical calling sequence 1949 $ DMCreate(PETSC_COMM_WORLD, &dm); 1950 $ DMSetType(dm, DMPLEX); 1951 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1952 $ DMClone(dm, §iondm); 1953 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1954 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1955 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1956 $ PetscSectionSetChart(section, pStart, pEnd); 1957 $ PetscSectionSetUp(section); 1958 $ DMSetLocalSection(sectiondm, section); 1959 $ PetscSectionDestroy(§ion); 1960 $ DMGetGlobalVector(sectiondm, &vec); 1961 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1962 $ DMPlexTopologyView(dm, viewer); 1963 $ DMPlexSectionView(dm, viewer, sectiondm); 1964 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1965 $ DMRestoreGlobalVector(sectiondm, &vec); 1966 $ DMDestroy(§iondm); 1967 $ DMDestroy(&dm); 1968 1969 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 1970 @*/ 1971 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1972 { 1973 PetscBool ishdf5; 1974 1975 PetscFunctionBegin; 1976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1977 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1978 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1979 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1980 /* Check consistency */ 1981 { 1982 PetscSection section; 1983 PetscBool includesConstraints; 1984 PetscInt m, m1; 1985 1986 PetscCall(VecGetLocalSize(vec, &m1)); 1987 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1988 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1989 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1990 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1991 PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m); 1992 } 1993 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1994 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1995 if (ishdf5) { 1996 #if defined(PETSC_HAVE_HDF5) 1997 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1998 #else 1999 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2000 #endif 2001 } 2002 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2003 PetscFunctionReturn(0); 2004 } 2005 2006 /*@ 2007 DMPlexLocalVectorView - Saves a local vector 2008 2009 Collective on DM 2010 2011 Input Parameters: 2012 + dm - The DM that represents the topology 2013 . viewer - The PetscViewer to save data with 2014 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2015 - vec - The local vector to be saved 2016 2017 Level: advanced 2018 2019 Notes: 2020 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2021 2022 Typical calling sequence 2023 $ DMCreate(PETSC_COMM_WORLD, &dm); 2024 $ DMSetType(dm, DMPLEX); 2025 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2026 $ DMClone(dm, §iondm); 2027 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2028 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2029 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2030 $ PetscSectionSetChart(section, pStart, pEnd); 2031 $ PetscSectionSetUp(section); 2032 $ DMSetLocalSection(sectiondm, section); 2033 $ DMGetLocalVector(sectiondm, &vec); 2034 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2035 $ DMPlexTopologyView(dm, viewer); 2036 $ DMPlexSectionView(dm, viewer, sectiondm); 2037 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2038 $ DMRestoreLocalVector(sectiondm, &vec); 2039 $ DMDestroy(§iondm); 2040 $ DMDestroy(&dm); 2041 2042 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 2043 @*/ 2044 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2045 { 2046 PetscBool ishdf5; 2047 2048 PetscFunctionBegin; 2049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2050 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2051 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2052 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2053 /* Check consistency */ 2054 { 2055 PetscSection section; 2056 PetscBool includesConstraints; 2057 PetscInt m, m1; 2058 2059 PetscCall(VecGetLocalSize(vec, &m1)); 2060 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2061 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2062 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2063 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2064 PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m); 2065 } 2066 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2067 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2068 if (ishdf5) { 2069 #if defined(PETSC_HAVE_HDF5) 2070 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2071 #else 2072 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2073 #endif 2074 } 2075 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2076 PetscFunctionReturn(0); 2077 } 2078 2079 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2080 { 2081 PetscBool ishdf5; 2082 2083 PetscFunctionBegin; 2084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2085 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2086 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2087 if (ishdf5) { 2088 #if defined(PETSC_HAVE_HDF5) 2089 PetscViewerFormat format; 2090 PetscCall(PetscViewerGetFormat(viewer, &format)); 2091 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2092 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2093 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2094 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2096 PetscFunctionReturn(0); 2097 #else 2098 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2099 #endif 2100 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2101 } 2102 2103 /*@ 2104 DMPlexTopologyLoad - Loads a topology into a DMPlex 2105 2106 Collective on DM 2107 2108 Input Parameters: 2109 + dm - The DM into which the topology is loaded 2110 - viewer - The PetscViewer for the saved topology 2111 2112 Output Parameters: 2113 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2114 2115 Level: advanced 2116 2117 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2118 @*/ 2119 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2120 { 2121 PetscBool ishdf5; 2122 2123 PetscFunctionBegin; 2124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2125 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2126 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2127 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2128 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2129 if (ishdf5) { 2130 #if defined(PETSC_HAVE_HDF5) 2131 PetscViewerFormat format; 2132 PetscCall(PetscViewerGetFormat(viewer, &format)); 2133 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2134 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2135 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2141 PetscFunctionReturn(0); 2142 } 2143 2144 /*@ 2145 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2146 2147 Collective on DM 2148 2149 Input Parameters: 2150 + dm - The DM into which the coordinates are loaded 2151 . viewer - The PetscViewer for the saved coordinates 2152 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2153 2154 Level: advanced 2155 2156 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2157 @*/ 2158 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2159 { 2160 PetscBool ishdf5; 2161 2162 PetscFunctionBegin; 2163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2164 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2165 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2166 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2167 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2168 if (ishdf5) { 2169 #if defined(PETSC_HAVE_HDF5) 2170 PetscViewerFormat format; 2171 PetscCall(PetscViewerGetFormat(viewer, &format)); 2172 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2173 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2174 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2175 #else 2176 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2177 #endif 2178 } 2179 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2180 PetscFunctionReturn(0); 2181 } 2182 2183 /*@ 2184 DMPlexLabelsLoad - Loads labels into a DMPlex 2185 2186 Collective on DM 2187 2188 Input Parameters: 2189 + dm - The DM into which the labels are loaded 2190 . viewer - The PetscViewer for the saved labels 2191 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2192 2193 Level: advanced 2194 2195 Notes: 2196 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2197 2198 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2199 @*/ 2200 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2201 { 2202 PetscBool ishdf5; 2203 2204 PetscFunctionBegin; 2205 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2206 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2207 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2208 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2209 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2210 if (ishdf5) { 2211 #if defined(PETSC_HAVE_HDF5) 2212 PetscViewerFormat format; 2213 2214 PetscCall(PetscViewerGetFormat(viewer, &format)); 2215 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2216 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2217 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2218 #else 2219 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2220 #endif 2221 } 2222 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2223 PetscFunctionReturn(0); 2224 } 2225 2226 /*@ 2227 DMPlexSectionLoad - Loads section into a DMPlex 2228 2229 Collective on DM 2230 2231 Input Parameters: 2232 + dm - The DM that represents the topology 2233 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2234 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2235 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2236 2237 Output Parameters 2238 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2239 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2240 2241 Level: advanced 2242 2243 Notes: 2244 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2245 2246 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2247 2248 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2249 2250 Example using 2 processes: 2251 $ NX (number of points on dm): 4 2252 $ sectionA : the on-disk section 2253 $ vecA : a vector associated with sectionA 2254 $ sectionB : sectiondm's local section constructed in this function 2255 $ vecB (local) : a vector associated with sectiondm's local section 2256 $ vecB (global) : a vector associated with sectiondm's global section 2257 $ 2258 $ rank 0 rank 1 2259 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2260 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2261 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2262 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2263 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2264 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2265 $ sectionB->atlasDof : 1 0 1 | 1 3 2266 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2267 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2268 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2269 $ 2270 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2271 2272 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView() 2273 @*/ 2274 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2282 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2283 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2284 if (localDofSF) PetscValidPointer(localDofSF, 6); 2285 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2286 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2287 if (ishdf5) { 2288 #if defined(PETSC_HAVE_HDF5) 2289 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2290 #else 2291 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2292 #endif 2293 } 2294 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2295 PetscFunctionReturn(0); 2296 } 2297 2298 /*@ 2299 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2300 2301 Collective on DM 2302 2303 Input Parameters: 2304 + dm - The DM that represents the topology 2305 . viewer - The PetscViewer that represents the on-disk vector data 2306 . sectiondm - The DM that contains the global section on which vec is defined 2307 . sf - The SF that migrates the on-disk vector data into vec 2308 - vec - The global vector to set values of 2309 2310 Level: advanced 2311 2312 Notes: 2313 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2314 2315 Typical calling sequence 2316 $ DMCreate(PETSC_COMM_WORLD, &dm); 2317 $ DMSetType(dm, DMPLEX); 2318 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2319 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2320 $ DMClone(dm, §iondm); 2321 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2322 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2323 $ DMGetGlobalVector(sectiondm, &vec); 2324 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2325 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2326 $ DMRestoreGlobalVector(sectiondm, &vec); 2327 $ PetscSFDestroy(&gsf); 2328 $ PetscSFDestroy(&sfX); 2329 $ DMDestroy(§iondm); 2330 $ DMDestroy(&dm); 2331 2332 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView() 2333 @*/ 2334 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2335 { 2336 PetscBool ishdf5; 2337 2338 PetscFunctionBegin; 2339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2341 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2342 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2343 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2344 /* Check consistency */ 2345 { 2346 PetscSection section; 2347 PetscBool includesConstraints; 2348 PetscInt m, m1; 2349 2350 PetscCall(VecGetLocalSize(vec, &m1)); 2351 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2352 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2353 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2354 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2355 PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m); 2356 } 2357 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2358 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2359 if (ishdf5) { 2360 #if defined(PETSC_HAVE_HDF5) 2361 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2362 #else 2363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2364 #endif 2365 } 2366 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2367 PetscFunctionReturn(0); 2368 } 2369 2370 /*@ 2371 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2372 2373 Collective on DM 2374 2375 Input Parameters: 2376 + dm - The DM that represents the topology 2377 . viewer - The PetscViewer that represents the on-disk vector data 2378 . sectiondm - The DM that contains the local section on which vec is defined 2379 . sf - The SF that migrates the on-disk vector data into vec 2380 - vec - The local vector to set values of 2381 2382 Level: advanced 2383 2384 Notes: 2385 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2386 2387 Typical calling sequence 2388 $ DMCreate(PETSC_COMM_WORLD, &dm); 2389 $ DMSetType(dm, DMPLEX); 2390 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2391 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2392 $ DMClone(dm, §iondm); 2393 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2394 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2395 $ DMGetLocalVector(sectiondm, &vec); 2396 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2397 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2398 $ DMRestoreLocalVector(sectiondm, &vec); 2399 $ PetscSFDestroy(&lsf); 2400 $ PetscSFDestroy(&sfX); 2401 $ DMDestroy(§iondm); 2402 $ DMDestroy(&dm); 2403 2404 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView() 2405 @*/ 2406 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2407 { 2408 PetscBool ishdf5; 2409 2410 PetscFunctionBegin; 2411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2412 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2413 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2414 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2415 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2416 /* Check consistency */ 2417 { 2418 PetscSection section; 2419 PetscBool includesConstraints; 2420 PetscInt m, m1; 2421 2422 PetscCall(VecGetLocalSize(vec, &m1)); 2423 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2424 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2425 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2426 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2427 PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m); 2428 } 2429 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2430 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2431 if (ishdf5) { 2432 #if defined(PETSC_HAVE_HDF5) 2433 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2434 #else 2435 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2436 #endif 2437 } 2438 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2439 PetscFunctionReturn(0); 2440 } 2441 2442 PetscErrorCode DMDestroy_Plex(DM dm) 2443 { 2444 DM_Plex *mesh = (DM_Plex*) dm->data; 2445 2446 PetscFunctionBegin; 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2451 if (--mesh->refct > 0) PetscFunctionReturn(0); 2452 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2453 PetscCall(PetscFree(mesh->cones)); 2454 PetscCall(PetscFree(mesh->coneOrientations)); 2455 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2456 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2457 PetscCall(PetscFree(mesh->supports)); 2458 PetscCall(PetscFree(mesh->facesTmp)); 2459 PetscCall(PetscFree(mesh->tetgenOpts)); 2460 PetscCall(PetscFree(mesh->triangleOpts)); 2461 PetscCall(PetscFree(mesh->transformType)); 2462 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2463 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2464 PetscCall(ISDestroy(&mesh->subpointIS)); 2465 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2466 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2467 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2468 PetscCall(ISDestroy(&mesh->anchorIS)); 2469 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2470 PetscCall(PetscFree(mesh->parents)); 2471 PetscCall(PetscFree(mesh->childIDs)); 2472 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2473 PetscCall(PetscFree(mesh->children)); 2474 PetscCall(DMDestroy(&mesh->referenceTree)); 2475 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2476 PetscCall(PetscFree(mesh->neighbors)); 2477 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2478 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2479 PetscCall(PetscFree(mesh)); 2480 PetscFunctionReturn(0); 2481 } 2482 2483 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2484 { 2485 PetscSection sectionGlobal; 2486 PetscInt bs = -1, mbs; 2487 PetscInt localSize; 2488 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2489 MatType mtype; 2490 ISLocalToGlobalMapping ltog; 2491 2492 PetscFunctionBegin; 2493 PetscCall(MatInitializePackage()); 2494 mtype = dm->mattype; 2495 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2496 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2497 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2498 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2499 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2500 PetscCall(MatSetType(*J, mtype)); 2501 PetscCall(MatSetFromOptions(*J)); 2502 PetscCall(MatGetBlockSize(*J, &mbs)); 2503 if (mbs > 1) bs = mbs; 2504 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2505 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2506 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2507 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2508 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2509 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2510 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2511 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2512 if (!isShell) { 2513 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2514 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2]; 2515 PetscInt pStart, pEnd, p, dof, cdof; 2516 2517 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2518 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2519 for (p = pStart; p < pEnd; ++p) { 2520 PetscInt bdof; 2521 2522 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2523 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2524 dof = dof < 0 ? -(dof+1) : dof; 2525 bdof = cdof && (dof-cdof) ? 1 : dof; 2526 if (dof) { 2527 if (bs < 0) {bs = bdof;} 2528 else if (bs != bdof) {bs = 1; break;} 2529 } 2530 } 2531 /* Must have same blocksize on all procs (some might have no points) */ 2532 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2533 bsLocal[1] = bs; 2534 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2535 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2536 else bs = bsMinMax[0]; 2537 bs = PetscMax(1,bs); 2538 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2539 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2540 PetscCall(MatSetBlockSize(*J, bs)); 2541 PetscCall(MatSetUp(*J)); 2542 } else { 2543 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2544 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2545 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2546 } 2547 } 2548 PetscCall(MatSetDM(*J, dm)); 2549 PetscFunctionReturn(0); 2550 } 2551 2552 /*@ 2553 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2554 2555 Not collective 2556 2557 Input Parameter: 2558 . mesh - The DMPlex 2559 2560 Output Parameters: 2561 . subsection - The subdomain section 2562 2563 Level: developer 2564 2565 .seealso: 2566 @*/ 2567 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2568 { 2569 DM_Plex *mesh = (DM_Plex*) dm->data; 2570 2571 PetscFunctionBegin; 2572 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2573 if (!mesh->subdomainSection) { 2574 PetscSection section; 2575 PetscSF sf; 2576 2577 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2578 PetscCall(DMGetLocalSection(dm,§ion)); 2579 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2580 PetscCall(PetscSFDestroy(&sf)); 2581 } 2582 *subsection = mesh->subdomainSection; 2583 PetscFunctionReturn(0); 2584 } 2585 2586 /*@ 2587 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2588 2589 Not collective 2590 2591 Input Parameter: 2592 . mesh - The DMPlex 2593 2594 Output Parameters: 2595 + pStart - The first mesh point 2596 - pEnd - The upper bound for mesh points 2597 2598 Level: beginner 2599 2600 .seealso: DMPlexCreate(), DMPlexSetChart() 2601 @*/ 2602 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2603 { 2604 DM_Plex *mesh = (DM_Plex*) dm->data; 2605 2606 PetscFunctionBegin; 2607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2608 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2609 PetscFunctionReturn(0); 2610 } 2611 2612 /*@ 2613 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2614 2615 Not collective 2616 2617 Input Parameters: 2618 + mesh - The DMPlex 2619 . pStart - The first mesh point 2620 - pEnd - The upper bound for mesh points 2621 2622 Output Parameters: 2623 2624 Level: beginner 2625 2626 .seealso: DMPlexCreate(), DMPlexGetChart() 2627 @*/ 2628 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2629 { 2630 DM_Plex *mesh = (DM_Plex*) dm->data; 2631 2632 PetscFunctionBegin; 2633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2634 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2635 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2636 PetscFunctionReturn(0); 2637 } 2638 2639 /*@ 2640 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2641 2642 Not collective 2643 2644 Input Parameters: 2645 + mesh - The DMPlex 2646 - p - The point, which must lie in the chart set with DMPlexSetChart() 2647 2648 Output Parameter: 2649 . size - The cone size for point p 2650 2651 Level: beginner 2652 2653 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 2654 @*/ 2655 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2656 { 2657 DM_Plex *mesh = (DM_Plex*) dm->data; 2658 2659 PetscFunctionBegin; 2660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2661 PetscValidIntPointer(size, 3); 2662 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2663 PetscFunctionReturn(0); 2664 } 2665 2666 /*@ 2667 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2668 2669 Not collective 2670 2671 Input Parameters: 2672 + mesh - The DMPlex 2673 . p - The point, which must lie in the chart set with DMPlexSetChart() 2674 - size - The cone size for point p 2675 2676 Output Parameter: 2677 2678 Note: 2679 This should be called after DMPlexSetChart(). 2680 2681 Level: beginner 2682 2683 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 2684 @*/ 2685 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2686 { 2687 DM_Plex *mesh = (DM_Plex*) dm->data; 2688 2689 PetscFunctionBegin; 2690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2691 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2692 2693 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 2694 PetscFunctionReturn(0); 2695 } 2696 2697 /*@ 2698 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2699 2700 Not collective 2701 2702 Input Parameters: 2703 + mesh - The DMPlex 2704 . p - The point, which must lie in the chart set with DMPlexSetChart() 2705 - size - The additional cone size for point p 2706 2707 Output Parameter: 2708 2709 Note: 2710 This should be called after DMPlexSetChart(). 2711 2712 Level: beginner 2713 2714 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 2715 @*/ 2716 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2717 { 2718 DM_Plex *mesh = (DM_Plex*) dm->data; 2719 PetscInt csize; 2720 2721 PetscFunctionBegin; 2722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2723 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2724 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &csize)); 2725 2726 mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize); 2727 PetscFunctionReturn(0); 2728 } 2729 2730 /*@C 2731 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2732 2733 Not collective 2734 2735 Input Parameters: 2736 + dm - The DMPlex 2737 - p - The point, which must lie in the chart set with DMPlexSetChart() 2738 2739 Output Parameter: 2740 . cone - An array of points which are on the in-edges for point p 2741 2742 Level: beginner 2743 2744 Fortran Notes: 2745 Since it returns an array, this routine is only available in Fortran 90, and you must 2746 include petsc.h90 in your code. 2747 You must also call DMPlexRestoreCone() after you finish using the returned array. 2748 DMPlexRestoreCone() is not needed/available in C. 2749 2750 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart() 2751 @*/ 2752 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2753 { 2754 DM_Plex *mesh = (DM_Plex*) dm->data; 2755 PetscInt off; 2756 2757 PetscFunctionBegin; 2758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2759 PetscValidPointer(cone, 3); 2760 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2761 *cone = &mesh->cones[off]; 2762 PetscFunctionReturn(0); 2763 } 2764 2765 /*@C 2766 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2767 2768 Not collective 2769 2770 Input Parameters: 2771 + dm - The DMPlex 2772 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2773 2774 Output Parameters: 2775 + pConesSection - PetscSection describing the layout of pCones 2776 - pCones - An array of points which are on the in-edges for the point set p 2777 2778 Level: intermediate 2779 2780 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart() 2781 @*/ 2782 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2783 { 2784 PetscSection cs, newcs; 2785 PetscInt *cones; 2786 PetscInt *newarr=NULL; 2787 PetscInt n; 2788 2789 PetscFunctionBegin; 2790 PetscCall(DMPlexGetCones(dm, &cones)); 2791 PetscCall(DMPlexGetConeSection(dm, &cs)); 2792 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2793 if (pConesSection) *pConesSection = newcs; 2794 if (pCones) { 2795 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2796 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2797 } 2798 PetscFunctionReturn(0); 2799 } 2800 2801 /*@ 2802 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2803 2804 Not collective 2805 2806 Input Parameters: 2807 + dm - The DMPlex 2808 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2809 2810 Output Parameter: 2811 . expandedPoints - An array of vertices recursively expanded from input points 2812 2813 Level: advanced 2814 2815 Notes: 2816 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2817 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2818 2819 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth() 2820 @*/ 2821 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2822 { 2823 IS *expandedPointsAll; 2824 PetscInt depth; 2825 2826 PetscFunctionBegin; 2827 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2828 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2829 PetscValidPointer(expandedPoints, 3); 2830 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2831 *expandedPoints = expandedPointsAll[0]; 2832 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2833 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2834 PetscFunctionReturn(0); 2835 } 2836 2837 /*@ 2838 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2839 2840 Not collective 2841 2842 Input Parameters: 2843 + dm - The DMPlex 2844 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2845 2846 Output Parameters: 2847 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2848 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2849 - sections - (optional) An array of sections which describe mappings from points to their cone points 2850 2851 Level: advanced 2852 2853 Notes: 2854 Like DMPlexGetConeTuple() but recursive. 2855 2856 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2857 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2858 2859 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2860 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2861 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2862 2863 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2864 @*/ 2865 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2866 { 2867 const PetscInt *arr0=NULL, *cone=NULL; 2868 PetscInt *arr=NULL, *newarr=NULL; 2869 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2870 IS *expandedPoints_; 2871 PetscSection *sections_; 2872 2873 PetscFunctionBegin; 2874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2875 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2876 if (depth) PetscValidIntPointer(depth, 3); 2877 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2878 if (sections) PetscValidPointer(sections, 5); 2879 PetscCall(ISGetLocalSize(points, &n)); 2880 PetscCall(ISGetIndices(points, &arr0)); 2881 PetscCall(DMPlexGetDepth(dm, &depth_)); 2882 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2883 PetscCall(PetscCalloc1(depth_, §ions_)); 2884 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2885 for (d=depth_-1; d>=0; d--) { 2886 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2887 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2888 for (i=0; i<n; i++) { 2889 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2890 if (arr[i] >= start && arr[i] < end) { 2891 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2892 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2893 } else { 2894 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2895 } 2896 } 2897 PetscCall(PetscSectionSetUp(sections_[d])); 2898 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2899 PetscCall(PetscMalloc1(newn, &newarr)); 2900 for (i=0; i<n; i++) { 2901 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2902 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2903 if (cn > 1) { 2904 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2905 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2906 } else { 2907 newarr[co] = arr[i]; 2908 } 2909 } 2910 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2911 arr = newarr; 2912 n = newn; 2913 } 2914 PetscCall(ISRestoreIndices(points, &arr0)); 2915 *depth = depth_; 2916 if (expandedPoints) *expandedPoints = expandedPoints_; 2917 else { 2918 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2919 PetscCall(PetscFree(expandedPoints_)); 2920 } 2921 if (sections) *sections = sections_; 2922 else { 2923 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2924 PetscCall(PetscFree(sections_)); 2925 } 2926 PetscFunctionReturn(0); 2927 } 2928 2929 /*@ 2930 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2931 2932 Not collective 2933 2934 Input Parameters: 2935 + dm - The DMPlex 2936 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2937 2938 Output Parameters: 2939 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2940 . expandedPoints - (optional) An array of recursively expanded cones 2941 - sections - (optional) An array of sections which describe mappings from points to their cone points 2942 2943 Level: advanced 2944 2945 Notes: 2946 See DMPlexGetConeRecursive() for details. 2947 2948 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2949 @*/ 2950 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2951 { 2952 PetscInt d, depth_; 2953 2954 PetscFunctionBegin; 2955 PetscCall(DMPlexGetDepth(dm, &depth_)); 2956 PetscCheckFalse(depth && *depth != depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2957 if (depth) *depth = 0; 2958 if (expandedPoints) { 2959 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2960 PetscCall(PetscFree(*expandedPoints)); 2961 } 2962 if (sections) { 2963 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2964 PetscCall(PetscFree(*sections)); 2965 } 2966 PetscFunctionReturn(0); 2967 } 2968 2969 /*@ 2970 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 2971 2972 Not collective 2973 2974 Input Parameters: 2975 + mesh - The DMPlex 2976 . p - The point, which must lie in the chart set with DMPlexSetChart() 2977 - cone - An array of points which are on the in-edges for point p 2978 2979 Output Parameter: 2980 2981 Note: 2982 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2983 2984 Level: beginner 2985 2986 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize() 2987 @*/ 2988 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 2989 { 2990 DM_Plex *mesh = (DM_Plex*) dm->data; 2991 PetscInt pStart, pEnd; 2992 PetscInt dof, off, c; 2993 2994 PetscFunctionBegin; 2995 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2996 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 2997 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 2998 if (dof) PetscValidIntPointer(cone, 3); 2999 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3000 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3001 for (c = 0; c < dof; ++c) { 3002 PetscCheckFalse((cone[c] < pStart) || (cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd); 3003 mesh->cones[off+c] = cone[c]; 3004 } 3005 PetscFunctionReturn(0); 3006 } 3007 3008 /*@C 3009 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3010 3011 Not collective 3012 3013 Input Parameters: 3014 + mesh - The DMPlex 3015 - p - The point, which must lie in the chart set with DMPlexSetChart() 3016 3017 Output Parameter: 3018 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3019 integer giving the prescription for cone traversal. 3020 3021 Level: beginner 3022 3023 Notes: 3024 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3025 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3026 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3027 with the identity. 3028 3029 Fortran Notes: 3030 Since it returns an array, this routine is only available in Fortran 90, and you must 3031 include petsc.h90 in your code. 3032 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3033 DMPlexRestoreConeOrientation() is not needed/available in C. 3034 3035 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 3036 @*/ 3037 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3038 { 3039 DM_Plex *mesh = (DM_Plex*) dm->data; 3040 PetscInt off; 3041 3042 PetscFunctionBegin; 3043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3044 if (PetscDefined(USE_DEBUG)) { 3045 PetscInt dof; 3046 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3047 if (dof) PetscValidPointer(coneOrientation, 3); 3048 } 3049 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3050 3051 *coneOrientation = &mesh->coneOrientations[off]; 3052 PetscFunctionReturn(0); 3053 } 3054 3055 /*@ 3056 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3057 3058 Not collective 3059 3060 Input Parameters: 3061 + mesh - The DMPlex 3062 . p - The point, which must lie in the chart set with DMPlexSetChart() 3063 - coneOrientation - An array of orientations 3064 Output Parameter: 3065 3066 Notes: 3067 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3068 3069 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3070 3071 Level: beginner 3072 3073 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3074 @*/ 3075 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3076 { 3077 DM_Plex *mesh = (DM_Plex*) dm->data; 3078 PetscInt pStart, pEnd; 3079 PetscInt dof, off, c; 3080 3081 PetscFunctionBegin; 3082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3083 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3084 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3085 if (dof) PetscValidIntPointer(coneOrientation, 3); 3086 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3087 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3088 for (c = 0; c < dof; ++c) { 3089 PetscInt cdof, o = coneOrientation[c]; 3090 3091 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3092 PetscCheckFalse(o && ((o < -(cdof+1)) || (o >= cdof)),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof); 3093 mesh->coneOrientations[off+c] = o; 3094 } 3095 PetscFunctionReturn(0); 3096 } 3097 3098 /*@ 3099 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3100 3101 Not collective 3102 3103 Input Parameters: 3104 + mesh - The DMPlex 3105 . p - The point, which must lie in the chart set with DMPlexSetChart() 3106 . conePos - The local index in the cone where the point should be put 3107 - conePoint - The mesh point to insert 3108 3109 Level: beginner 3110 3111 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3112 @*/ 3113 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3114 { 3115 DM_Plex *mesh = (DM_Plex*) dm->data; 3116 PetscInt pStart, pEnd; 3117 PetscInt dof, off; 3118 3119 PetscFunctionBegin; 3120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3121 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3122 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3123 PetscCheckFalse((conePoint < pStart) || (conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd); 3124 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3125 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3126 PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 3127 mesh->cones[off+conePos] = conePoint; 3128 PetscFunctionReturn(0); 3129 } 3130 3131 /*@ 3132 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3133 3134 Not collective 3135 3136 Input Parameters: 3137 + mesh - The DMPlex 3138 . p - The point, which must lie in the chart set with DMPlexSetChart() 3139 . conePos - The local index in the cone where the point should be put 3140 - coneOrientation - The point orientation to insert 3141 3142 Level: beginner 3143 3144 Notes: 3145 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3146 3147 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3148 @*/ 3149 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3150 { 3151 DM_Plex *mesh = (DM_Plex*) dm->data; 3152 PetscInt pStart, pEnd; 3153 PetscInt dof, off; 3154 3155 PetscFunctionBegin; 3156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3157 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3158 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3159 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3160 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3161 PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 3162 mesh->coneOrientations[off+conePos] = coneOrientation; 3163 PetscFunctionReturn(0); 3164 } 3165 3166 /*@ 3167 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3168 3169 Not collective 3170 3171 Input Parameters: 3172 + mesh - The DMPlex 3173 - p - The point, which must lie in the chart set with DMPlexSetChart() 3174 3175 Output Parameter: 3176 . size - The support size for point p 3177 3178 Level: beginner 3179 3180 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 3181 @*/ 3182 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3183 { 3184 DM_Plex *mesh = (DM_Plex*) dm->data; 3185 3186 PetscFunctionBegin; 3187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3188 PetscValidIntPointer(size, 3); 3189 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3190 PetscFunctionReturn(0); 3191 } 3192 3193 /*@ 3194 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3195 3196 Not collective 3197 3198 Input Parameters: 3199 + mesh - The DMPlex 3200 . p - The point, which must lie in the chart set with DMPlexSetChart() 3201 - size - The support size for point p 3202 3203 Output Parameter: 3204 3205 Note: 3206 This should be called after DMPlexSetChart(). 3207 3208 Level: beginner 3209 3210 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 3211 @*/ 3212 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3213 { 3214 DM_Plex *mesh = (DM_Plex*) dm->data; 3215 3216 PetscFunctionBegin; 3217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3218 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3219 3220 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 3221 PetscFunctionReturn(0); 3222 } 3223 3224 /*@C 3225 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3226 3227 Not collective 3228 3229 Input Parameters: 3230 + mesh - The DMPlex 3231 - p - The point, which must lie in the chart set with DMPlexSetChart() 3232 3233 Output Parameter: 3234 . support - An array of points which are on the out-edges for point p 3235 3236 Level: beginner 3237 3238 Fortran Notes: 3239 Since it returns an array, this routine is only available in Fortran 90, and you must 3240 include petsc.h90 in your code. 3241 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3242 DMPlexRestoreSupport() is not needed/available in C. 3243 3244 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart() 3245 @*/ 3246 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3247 { 3248 DM_Plex *mesh = (DM_Plex*) dm->data; 3249 PetscInt off; 3250 3251 PetscFunctionBegin; 3252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3253 PetscValidPointer(support, 3); 3254 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3255 *support = &mesh->supports[off]; 3256 PetscFunctionReturn(0); 3257 } 3258 3259 /*@ 3260 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3261 3262 Not collective 3263 3264 Input Parameters: 3265 + mesh - The DMPlex 3266 . p - The point, which must lie in the chart set with DMPlexSetChart() 3267 - support - An array of points which are on the out-edges for point p 3268 3269 Output Parameter: 3270 3271 Note: 3272 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3273 3274 Level: beginner 3275 3276 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 3277 @*/ 3278 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3279 { 3280 DM_Plex *mesh = (DM_Plex*) dm->data; 3281 PetscInt pStart, pEnd; 3282 PetscInt dof, off, c; 3283 3284 PetscFunctionBegin; 3285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3286 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3287 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3288 if (dof) PetscValidIntPointer(support, 3); 3289 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3290 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3291 for (c = 0; c < dof; ++c) { 3292 PetscCheckFalse((support[c] < pStart) || (support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd); 3293 mesh->supports[off+c] = support[c]; 3294 } 3295 PetscFunctionReturn(0); 3296 } 3297 3298 /*@ 3299 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3300 3301 Not collective 3302 3303 Input Parameters: 3304 + mesh - The DMPlex 3305 . p - The point, which must lie in the chart set with DMPlexSetChart() 3306 . supportPos - The local index in the cone where the point should be put 3307 - supportPoint - The mesh point to insert 3308 3309 Level: beginner 3310 3311 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3312 @*/ 3313 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3314 { 3315 DM_Plex *mesh = (DM_Plex*) dm->data; 3316 PetscInt pStart, pEnd; 3317 PetscInt dof, off; 3318 3319 PetscFunctionBegin; 3320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3321 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3322 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3323 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3324 PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 3325 PetscCheckFalse((supportPoint < pStart) || (supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd); 3326 PetscCheckFalse(supportPos >= dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof); 3327 mesh->supports[off+supportPos] = supportPoint; 3328 PetscFunctionReturn(0); 3329 } 3330 3331 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3332 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3333 { 3334 switch (ct) { 3335 case DM_POLYTOPE_SEGMENT: 3336 if (o == -1) return -2; 3337 break; 3338 case DM_POLYTOPE_TRIANGLE: 3339 if (o == -3) return -1; 3340 if (o == -2) return -3; 3341 if (o == -1) return -2; 3342 break; 3343 case DM_POLYTOPE_QUADRILATERAL: 3344 if (o == -4) return -2; 3345 if (o == -3) return -1; 3346 if (o == -2) return -4; 3347 if (o == -1) return -3; 3348 break; 3349 default: return o; 3350 } 3351 return o; 3352 } 3353 3354 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3355 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3356 { 3357 switch (ct) { 3358 case DM_POLYTOPE_SEGMENT: 3359 if ((o == -2) || (o == 1)) return -1; 3360 if (o == -1) return 0; 3361 break; 3362 case DM_POLYTOPE_TRIANGLE: 3363 if (o == -3) return -2; 3364 if (o == -2) return -1; 3365 if (o == -1) return -3; 3366 break; 3367 case DM_POLYTOPE_QUADRILATERAL: 3368 if (o == -4) return -2; 3369 if (o == -3) return -1; 3370 if (o == -2) return -4; 3371 if (o == -1) return -3; 3372 break; 3373 default: return o; 3374 } 3375 return o; 3376 } 3377 3378 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3379 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3380 { 3381 PetscInt pStart, pEnd, p; 3382 3383 PetscFunctionBegin; 3384 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3385 for (p = pStart; p < pEnd; ++p) { 3386 const PetscInt *cone, *ornt; 3387 PetscInt coneSize, c; 3388 3389 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3390 PetscCall(DMPlexGetCone(dm, p, &cone)); 3391 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3392 for (c = 0; c < coneSize; ++c) { 3393 DMPolytopeType ct; 3394 const PetscInt o = ornt[c]; 3395 3396 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3397 switch (ct) { 3398 case DM_POLYTOPE_SEGMENT: 3399 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3400 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3401 break; 3402 case DM_POLYTOPE_TRIANGLE: 3403 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3404 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3405 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3406 break; 3407 case DM_POLYTOPE_QUADRILATERAL: 3408 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3409 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3410 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3411 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3412 break; 3413 default: break; 3414 } 3415 } 3416 } 3417 PetscFunctionReturn(0); 3418 } 3419 3420 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3421 { 3422 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3423 PetscInt *closure; 3424 const PetscInt *tmp = NULL, *tmpO = NULL; 3425 PetscInt off = 0, tmpSize, t; 3426 3427 PetscFunctionBeginHot; 3428 if (ornt) { 3429 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3430 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3431 } 3432 if (*points) { 3433 closure = *points; 3434 } else { 3435 PetscInt maxConeSize, maxSupportSize; 3436 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3437 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3438 } 3439 if (useCone) { 3440 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3441 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3442 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3443 } else { 3444 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3445 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3446 } 3447 if (ct == DM_POLYTOPE_UNKNOWN) { 3448 closure[off++] = p; 3449 closure[off++] = 0; 3450 for (t = 0; t < tmpSize; ++t) { 3451 closure[off++] = tmp[t]; 3452 closure[off++] = tmpO ? tmpO[t] : 0; 3453 } 3454 } else { 3455 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3456 3457 /* We assume that cells with a valid type have faces with a valid type */ 3458 closure[off++] = p; 3459 closure[off++] = ornt; 3460 for (t = 0; t < tmpSize; ++t) { 3461 DMPolytopeType ft; 3462 3463 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3464 closure[off++] = tmp[arr[t]]; 3465 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3466 } 3467 } 3468 if (numPoints) *numPoints = tmpSize+1; 3469 if (points) *points = closure; 3470 PetscFunctionReturn(0); 3471 } 3472 3473 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3474 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3475 { 3476 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3477 const PetscInt *cone, *ornt; 3478 PetscInt *pts, *closure = NULL; 3479 DMPolytopeType ft; 3480 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3481 PetscInt dim, coneSize, c, d, clSize, cl; 3482 3483 PetscFunctionBeginHot; 3484 PetscCall(DMGetDimension(dm, &dim)); 3485 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3486 PetscCall(DMPlexGetCone(dm, point, &cone)); 3487 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3488 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3489 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3490 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3491 maxSize = PetscMax(coneSeries, supportSeries); 3492 if (*points) {pts = *points;} 3493 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3494 c = 0; 3495 pts[c++] = point; 3496 pts[c++] = o; 3497 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3498 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3499 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3500 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3501 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3502 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3503 for (d = 2; d < coneSize; ++d) { 3504 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3505 pts[c++] = cone[arr[d*2+0]]; 3506 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3507 } 3508 if (dim >= 3) { 3509 for (d = 2; d < coneSize; ++d) { 3510 const PetscInt fpoint = cone[arr[d*2+0]]; 3511 const PetscInt *fcone, *fornt; 3512 PetscInt fconeSize, fc, i; 3513 3514 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3515 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3516 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3517 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3518 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3519 for (fc = 0; fc < fconeSize; ++fc) { 3520 const PetscInt cp = fcone[farr[fc*2+0]]; 3521 const PetscInt co = farr[fc*2+1]; 3522 3523 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3524 if (i == c) { 3525 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3526 pts[c++] = cp; 3527 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3528 } 3529 } 3530 } 3531 } 3532 *numPoints = c/2; 3533 *points = pts; 3534 PetscFunctionReturn(0); 3535 } 3536 3537 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3538 { 3539 DMPolytopeType ct; 3540 PetscInt *closure, *fifo; 3541 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3542 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3543 PetscInt depth, maxSize; 3544 3545 PetscFunctionBeginHot; 3546 PetscCall(DMPlexGetDepth(dm, &depth)); 3547 if (depth == 1) { 3548 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3549 PetscFunctionReturn(0); 3550 } 3551 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3552 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3553 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3554 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3555 PetscFunctionReturn(0); 3556 } 3557 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3558 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3559 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3560 maxSize = PetscMax(coneSeries, supportSeries); 3561 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3562 if (*points) {closure = *points;} 3563 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3564 closure[closureSize++] = p; 3565 closure[closureSize++] = ornt; 3566 fifo[fifoSize++] = p; 3567 fifo[fifoSize++] = ornt; 3568 fifo[fifoSize++] = ct; 3569 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3570 while (fifoSize - fifoStart) { 3571 const PetscInt q = fifo[fifoStart++]; 3572 const PetscInt o = fifo[fifoStart++]; 3573 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3574 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3575 const PetscInt *tmp, *tmpO; 3576 PetscInt tmpSize, t; 3577 3578 if (PetscDefined(USE_DEBUG)) { 3579 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3580 PetscCheckFalse(o && (o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %D not in [%D,%D) for %s %D", o, -nO, nO, DMPolytopeTypes[qt], q); 3581 } 3582 if (useCone) { 3583 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3584 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3585 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3586 } else { 3587 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3588 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3589 tmpO = NULL; 3590 } 3591 for (t = 0; t < tmpSize; ++t) { 3592 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3593 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3594 const PetscInt cp = tmp[ip]; 3595 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3596 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3597 PetscInt c; 3598 3599 /* Check for duplicate */ 3600 for (c = 0; c < closureSize; c += 2) { 3601 if (closure[c] == cp) break; 3602 } 3603 if (c == closureSize) { 3604 closure[closureSize++] = cp; 3605 closure[closureSize++] = co; 3606 fifo[fifoSize++] = cp; 3607 fifo[fifoSize++] = co; 3608 fifo[fifoSize++] = ct; 3609 } 3610 } 3611 } 3612 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3613 if (numPoints) *numPoints = closureSize/2; 3614 if (points) *points = closure; 3615 PetscFunctionReturn(0); 3616 } 3617 3618 /*@C 3619 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3620 3621 Not collective 3622 3623 Input Parameters: 3624 + dm - The DMPlex 3625 . p - The mesh point 3626 - useCone - PETSC_TRUE for the closure, otherwise return the star 3627 3628 Input/Output Parameter: 3629 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3630 if NULL on input, internal storage will be returned, otherwise the provided array is used 3631 3632 Output Parameter: 3633 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3634 3635 Note: 3636 If using internal storage (points is NULL on input), each call overwrites the last output. 3637 3638 Fortran Notes: 3639 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3640 3641 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3642 3643 Level: beginner 3644 3645 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3646 @*/ 3647 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3648 { 3649 PetscFunctionBeginHot; 3650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3651 if (numPoints) PetscValidIntPointer(numPoints, 4); 3652 if (points) PetscValidPointer(points, 5); 3653 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3654 PetscFunctionReturn(0); 3655 } 3656 3657 /*@C 3658 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3659 3660 Not collective 3661 3662 Input Parameters: 3663 + dm - The DMPlex 3664 . p - The mesh point 3665 . useCone - PETSC_TRUE for the closure, otherwise return the star 3666 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3667 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3668 3669 Note: 3670 If not using internal storage (points is not NULL on input), this call is unnecessary 3671 3672 Fortran Notes: 3673 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3674 3675 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3676 3677 Level: beginner 3678 3679 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3680 @*/ 3681 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3682 { 3683 PetscFunctionBeginHot; 3684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3685 if (numPoints) *numPoints = 0; 3686 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3687 PetscFunctionReturn(0); 3688 } 3689 3690 /*@ 3691 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3692 3693 Not collective 3694 3695 Input Parameter: 3696 . mesh - The DMPlex 3697 3698 Output Parameters: 3699 + maxConeSize - The maximum number of in-edges 3700 - maxSupportSize - The maximum number of out-edges 3701 3702 Level: beginner 3703 3704 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 3705 @*/ 3706 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3707 { 3708 DM_Plex *mesh = (DM_Plex*) dm->data; 3709 3710 PetscFunctionBegin; 3711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3712 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 3713 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 3714 PetscFunctionReturn(0); 3715 } 3716 3717 PetscErrorCode DMSetUp_Plex(DM dm) 3718 { 3719 DM_Plex *mesh = (DM_Plex*) dm->data; 3720 PetscInt size; 3721 3722 PetscFunctionBegin; 3723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3724 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3725 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3726 PetscCall(PetscMalloc1(size, &mesh->cones)); 3727 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3728 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3729 if (mesh->maxSupportSize) { 3730 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3731 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3732 PetscCall(PetscMalloc1(size, &mesh->supports)); 3733 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3734 } 3735 PetscFunctionReturn(0); 3736 } 3737 3738 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3739 { 3740 PetscFunctionBegin; 3741 if (subdm) PetscCall(DMClone(dm, subdm)); 3742 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3743 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3744 if (dm->useNatural && dm->sfMigration) { 3745 PetscSF sfMigrationInv,sfNatural; 3746 PetscSection section, sectionSeq; 3747 3748 (*subdm)->sfMigration = dm->sfMigration; 3749 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3750 PetscCall(DMGetLocalSection((*subdm), §ion)); 3751 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3752 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3753 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3754 3755 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3756 (*subdm)->sfNatural = sfNatural; 3757 PetscCall(PetscSectionDestroy(§ionSeq)); 3758 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3759 } 3760 PetscFunctionReturn(0); 3761 } 3762 3763 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3764 { 3765 PetscInt i = 0; 3766 3767 PetscFunctionBegin; 3768 PetscCall(DMClone(dms[0], superdm)); 3769 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3770 (*superdm)->useNatural = PETSC_FALSE; 3771 for (i = 0; i < len; i++) { 3772 if (dms[i]->useNatural && dms[i]->sfMigration) { 3773 PetscSF sfMigrationInv,sfNatural; 3774 PetscSection section, sectionSeq; 3775 3776 (*superdm)->sfMigration = dms[i]->sfMigration; 3777 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3778 (*superdm)->useNatural = PETSC_TRUE; 3779 PetscCall(DMGetLocalSection((*superdm), §ion)); 3780 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3781 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3782 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3783 3784 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3785 (*superdm)->sfNatural = sfNatural; 3786 PetscCall(PetscSectionDestroy(§ionSeq)); 3787 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3788 break; 3789 } 3790 } 3791 PetscFunctionReturn(0); 3792 } 3793 3794 /*@ 3795 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3796 3797 Not collective 3798 3799 Input Parameter: 3800 . mesh - The DMPlex 3801 3802 Output Parameter: 3803 3804 Note: 3805 This should be called after all calls to DMPlexSetCone() 3806 3807 Level: beginner 3808 3809 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 3810 @*/ 3811 PetscErrorCode DMPlexSymmetrize(DM dm) 3812 { 3813 DM_Plex *mesh = (DM_Plex*) dm->data; 3814 PetscInt *offsets; 3815 PetscInt supportSize; 3816 PetscInt pStart, pEnd, p; 3817 3818 PetscFunctionBegin; 3819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3820 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3821 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3822 /* Calculate support sizes */ 3823 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3824 for (p = pStart; p < pEnd; ++p) { 3825 PetscInt dof, off, c; 3826 3827 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3828 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3829 for (c = off; c < off+dof; ++c) { 3830 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3831 } 3832 } 3833 for (p = pStart; p < pEnd; ++p) { 3834 PetscInt dof; 3835 3836 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3837 3838 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 3839 } 3840 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3841 /* Calculate supports */ 3842 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3843 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3844 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3845 for (p = pStart; p < pEnd; ++p) { 3846 PetscInt dof, off, c; 3847 3848 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3849 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3850 for (c = off; c < off+dof; ++c) { 3851 const PetscInt q = mesh->cones[c]; 3852 PetscInt offS; 3853 3854 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3855 3856 mesh->supports[offS+offsets[q]] = p; 3857 ++offsets[q]; 3858 } 3859 } 3860 PetscCall(PetscFree(offsets)); 3861 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3862 PetscFunctionReturn(0); 3863 } 3864 3865 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3866 { 3867 IS stratumIS; 3868 3869 PetscFunctionBegin; 3870 if (pStart >= pEnd) PetscFunctionReturn(0); 3871 if (PetscDefined(USE_DEBUG)) { 3872 PetscInt qStart, qEnd, numLevels, level; 3873 PetscBool overlap = PETSC_FALSE; 3874 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3875 for (level = 0; level < numLevels; level++) { 3876 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3877 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3878 } 3879 PetscCheck(!overlap,PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %D range [%D,%D) overlaps with depth %D range [%D,%D)", depth, pStart, pEnd, level, qStart, qEnd); 3880 } 3881 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3882 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3883 PetscCall(ISDestroy(&stratumIS)); 3884 PetscFunctionReturn(0); 3885 } 3886 3887 /*@ 3888 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3889 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3890 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3891 the DAG. 3892 3893 Collective on dm 3894 3895 Input Parameter: 3896 . mesh - The DMPlex 3897 3898 Output Parameter: 3899 3900 Notes: 3901 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3902 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3903 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3904 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3905 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3906 3907 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3908 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3909 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 3910 to interpolate only that one (e0), so that 3911 $ cone(c0) = {e0, v2} 3912 $ cone(e0) = {v0, v1} 3913 If DMPlexStratify() is run on this mesh, it will give depths 3914 $ depth 0 = {v0, v1, v2} 3915 $ depth 1 = {e0, c0} 3916 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3917 3918 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3919 3920 Level: beginner 3921 3922 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes() 3923 @*/ 3924 PetscErrorCode DMPlexStratify(DM dm) 3925 { 3926 DM_Plex *mesh = (DM_Plex*) dm->data; 3927 DMLabel label; 3928 PetscInt pStart, pEnd, p; 3929 PetscInt numRoots = 0, numLeaves = 0; 3930 3931 PetscFunctionBegin; 3932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3933 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3934 3935 /* Create depth label */ 3936 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3937 PetscCall(DMCreateLabel(dm, "depth")); 3938 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3939 3940 { 3941 /* Initialize roots and count leaves */ 3942 PetscInt sMin = PETSC_MAX_INT; 3943 PetscInt sMax = PETSC_MIN_INT; 3944 PetscInt coneSize, supportSize; 3945 3946 for (p = pStart; p < pEnd; ++p) { 3947 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3948 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3949 if (!coneSize && supportSize) { 3950 sMin = PetscMin(p, sMin); 3951 sMax = PetscMax(p, sMax); 3952 ++numRoots; 3953 } else if (!supportSize && coneSize) { 3954 ++numLeaves; 3955 } else if (!supportSize && !coneSize) { 3956 /* Isolated points */ 3957 sMin = PetscMin(p, sMin); 3958 sMax = PetscMax(p, sMax); 3959 } 3960 } 3961 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3962 } 3963 3964 if (numRoots + numLeaves == (pEnd - pStart)) { 3965 PetscInt sMin = PETSC_MAX_INT; 3966 PetscInt sMax = PETSC_MIN_INT; 3967 PetscInt coneSize, supportSize; 3968 3969 for (p = pStart; p < pEnd; ++p) { 3970 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3971 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3972 if (!supportSize && coneSize) { 3973 sMin = PetscMin(p, sMin); 3974 sMax = PetscMax(p, sMax); 3975 } 3976 } 3977 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3978 } else { 3979 PetscInt level = 0; 3980 PetscInt qStart, qEnd, q; 3981 3982 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3983 while (qEnd > qStart) { 3984 PetscInt sMin = PETSC_MAX_INT; 3985 PetscInt sMax = PETSC_MIN_INT; 3986 3987 for (q = qStart; q < qEnd; ++q) { 3988 const PetscInt *support; 3989 PetscInt supportSize, s; 3990 3991 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3992 PetscCall(DMPlexGetSupport(dm, q, &support)); 3993 for (s = 0; s < supportSize; ++s) { 3994 sMin = PetscMin(support[s], sMin); 3995 sMax = PetscMax(support[s], sMax); 3996 } 3997 } 3998 PetscCall(DMLabelGetNumValues(label, &level)); 3999 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4000 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4001 } 4002 } 4003 { /* just in case there is an empty process */ 4004 PetscInt numValues, maxValues = 0, v; 4005 4006 PetscCall(DMLabelGetNumValues(label, &numValues)); 4007 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4008 for (v = numValues; v < maxValues; v++) { 4009 PetscCall(DMLabelAddStratum(label, v)); 4010 } 4011 } 4012 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4013 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4014 PetscFunctionReturn(0); 4015 } 4016 4017 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4018 { 4019 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4020 PetscInt dim, depth, pheight, coneSize; 4021 4022 PetscFunctionBeginHot; 4023 PetscCall(DMGetDimension(dm, &dim)); 4024 PetscCall(DMPlexGetDepth(dm, &depth)); 4025 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4026 pheight = depth - pdepth; 4027 if (depth <= 1) { 4028 switch (pdepth) { 4029 case 0: ct = DM_POLYTOPE_POINT;break; 4030 case 1: 4031 switch (coneSize) { 4032 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4033 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4034 case 4: 4035 switch (dim) { 4036 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4037 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4038 default: break; 4039 } 4040 break; 4041 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4042 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4043 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4044 default: break; 4045 } 4046 } 4047 } else { 4048 if (pdepth == 0) { 4049 ct = DM_POLYTOPE_POINT; 4050 } else if (pheight == 0) { 4051 switch (dim) { 4052 case 1: 4053 switch (coneSize) { 4054 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4055 default: break; 4056 } 4057 break; 4058 case 2: 4059 switch (coneSize) { 4060 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4061 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4062 default: break; 4063 } 4064 break; 4065 case 3: 4066 switch (coneSize) { 4067 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4068 case 5: 4069 { 4070 const PetscInt *cone; 4071 PetscInt faceConeSize; 4072 4073 PetscCall(DMPlexGetCone(dm, p, &cone)); 4074 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4075 switch (faceConeSize) { 4076 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4077 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4078 } 4079 } 4080 break; 4081 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4082 default: break; 4083 } 4084 break; 4085 default: break; 4086 } 4087 } else if (pheight > 0) { 4088 switch (coneSize) { 4089 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4090 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4091 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4092 default: break; 4093 } 4094 } 4095 } 4096 *pt = ct; 4097 PetscFunctionReturn(0); 4098 } 4099 4100 /*@ 4101 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4102 4103 Collective on dm 4104 4105 Input Parameter: 4106 . mesh - The DMPlex 4107 4108 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4109 4110 Level: developer 4111 4112 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4113 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4114 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4115 4116 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel() 4117 @*/ 4118 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4119 { 4120 DM_Plex *mesh; 4121 DMLabel ctLabel; 4122 PetscInt pStart, pEnd, p; 4123 4124 PetscFunctionBegin; 4125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4126 mesh = (DM_Plex *) dm->data; 4127 PetscCall(DMCreateLabel(dm, "celltype")); 4128 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4129 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4130 for (p = pStart; p < pEnd; ++p) { 4131 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4132 PetscInt pdepth; 4133 4134 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4135 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4136 PetscCheckFalse(ct == DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p); 4137 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4138 } 4139 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4140 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4141 PetscFunctionReturn(0); 4142 } 4143 4144 /*@C 4145 DMPlexGetJoin - Get an array for the join of the set of points 4146 4147 Not Collective 4148 4149 Input Parameters: 4150 + dm - The DMPlex object 4151 . numPoints - The number of input points for the join 4152 - points - The input points 4153 4154 Output Parameters: 4155 + numCoveredPoints - The number of points in the join 4156 - coveredPoints - The points in the join 4157 4158 Level: intermediate 4159 4160 Note: Currently, this is restricted to a single level join 4161 4162 Fortran Notes: 4163 Since it returns an array, this routine is only available in Fortran 90, and you must 4164 include petsc.h90 in your code. 4165 4166 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4167 4168 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 4169 @*/ 4170 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4171 { 4172 DM_Plex *mesh = (DM_Plex*) dm->data; 4173 PetscInt *join[2]; 4174 PetscInt joinSize, i = 0; 4175 PetscInt dof, off, p, c, m; 4176 4177 PetscFunctionBegin; 4178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4179 PetscValidIntPointer(points, 3); 4180 PetscValidIntPointer(numCoveredPoints, 4); 4181 PetscValidPointer(coveredPoints, 5); 4182 PetscCall(DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0])); 4183 PetscCall(DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1])); 4184 /* Copy in support of first point */ 4185 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4186 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4187 for (joinSize = 0; joinSize < dof; ++joinSize) { 4188 join[i][joinSize] = mesh->supports[off+joinSize]; 4189 } 4190 /* Check each successive support */ 4191 for (p = 1; p < numPoints; ++p) { 4192 PetscInt newJoinSize = 0; 4193 4194 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4195 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4196 for (c = 0; c < dof; ++c) { 4197 const PetscInt point = mesh->supports[off+c]; 4198 4199 for (m = 0; m < joinSize; ++m) { 4200 if (point == join[i][m]) { 4201 join[1-i][newJoinSize++] = point; 4202 break; 4203 } 4204 } 4205 } 4206 joinSize = newJoinSize; 4207 i = 1-i; 4208 } 4209 *numCoveredPoints = joinSize; 4210 *coveredPoints = join[i]; 4211 PetscCall(DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i])); 4212 PetscFunctionReturn(0); 4213 } 4214 4215 /*@C 4216 DMPlexRestoreJoin - Restore an array for the join of the set of points 4217 4218 Not Collective 4219 4220 Input Parameters: 4221 + dm - The DMPlex object 4222 . numPoints - The number of input points for the join 4223 - points - The input points 4224 4225 Output Parameters: 4226 + numCoveredPoints - The number of points in the join 4227 - coveredPoints - The points in the join 4228 4229 Fortran Notes: 4230 Since it returns an array, this routine is only available in Fortran 90, and you must 4231 include petsc.h90 in your code. 4232 4233 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4234 4235 Level: intermediate 4236 4237 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 4238 @*/ 4239 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4240 { 4241 PetscFunctionBegin; 4242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4243 if (points) PetscValidIntPointer(points,3); 4244 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4245 PetscValidPointer(coveredPoints, 5); 4246 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4247 if (numCoveredPoints) *numCoveredPoints = 0; 4248 PetscFunctionReturn(0); 4249 } 4250 4251 /*@C 4252 DMPlexGetFullJoin - Get an array for the join of the set of points 4253 4254 Not Collective 4255 4256 Input Parameters: 4257 + dm - The DMPlex object 4258 . numPoints - The number of input points for the join 4259 - points - The input points 4260 4261 Output Parameters: 4262 + numCoveredPoints - The number of points in the join 4263 - coveredPoints - The points in the join 4264 4265 Fortran Notes: 4266 Since it returns an array, this routine is only available in Fortran 90, and you must 4267 include petsc.h90 in your code. 4268 4269 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4270 4271 Level: intermediate 4272 4273 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 4274 @*/ 4275 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4276 { 4277 DM_Plex *mesh = (DM_Plex*) dm->data; 4278 PetscInt *offsets, **closures; 4279 PetscInt *join[2]; 4280 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4281 PetscInt p, d, c, m, ms; 4282 4283 PetscFunctionBegin; 4284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4285 PetscValidIntPointer(points, 3); 4286 PetscValidIntPointer(numCoveredPoints, 4); 4287 PetscValidPointer(coveredPoints, 5); 4288 4289 PetscCall(DMPlexGetDepth(dm, &depth)); 4290 PetscCall(PetscCalloc1(numPoints, &closures)); 4291 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4292 ms = mesh->maxSupportSize; 4293 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4294 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4295 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4296 4297 for (p = 0; p < numPoints; ++p) { 4298 PetscInt closureSize; 4299 4300 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4301 4302 offsets[p*(depth+2)+0] = 0; 4303 for (d = 0; d < depth+1; ++d) { 4304 PetscInt pStart, pEnd, i; 4305 4306 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4307 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4308 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4309 offsets[p*(depth+2)+d+1] = i; 4310 break; 4311 } 4312 } 4313 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4314 } 4315 PetscCheckFalse(offsets[p*(depth+2)+depth+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize); 4316 } 4317 for (d = 0; d < depth+1; ++d) { 4318 PetscInt dof; 4319 4320 /* Copy in support of first point */ 4321 dof = offsets[d+1] - offsets[d]; 4322 for (joinSize = 0; joinSize < dof; ++joinSize) { 4323 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4324 } 4325 /* Check each successive cone */ 4326 for (p = 1; p < numPoints && joinSize; ++p) { 4327 PetscInt newJoinSize = 0; 4328 4329 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4330 for (c = 0; c < dof; ++c) { 4331 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4332 4333 for (m = 0; m < joinSize; ++m) { 4334 if (point == join[i][m]) { 4335 join[1-i][newJoinSize++] = point; 4336 break; 4337 } 4338 } 4339 } 4340 joinSize = newJoinSize; 4341 i = 1-i; 4342 } 4343 if (joinSize) break; 4344 } 4345 *numCoveredPoints = joinSize; 4346 *coveredPoints = join[i]; 4347 for (p = 0; p < numPoints; ++p) { 4348 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4349 } 4350 PetscCall(PetscFree(closures)); 4351 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4352 PetscCall(DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i])); 4353 PetscFunctionReturn(0); 4354 } 4355 4356 /*@C 4357 DMPlexGetMeet - Get an array for the meet of the set of points 4358 4359 Not Collective 4360 4361 Input Parameters: 4362 + dm - The DMPlex object 4363 . numPoints - The number of input points for the meet 4364 - points - The input points 4365 4366 Output Parameters: 4367 + numCoveredPoints - The number of points in the meet 4368 - coveredPoints - The points in the meet 4369 4370 Level: intermediate 4371 4372 Note: Currently, this is restricted to a single level meet 4373 4374 Fortran Notes: 4375 Since it returns an array, this routine is only available in Fortran 90, and you must 4376 include petsc.h90 in your code. 4377 4378 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4379 4380 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 4381 @*/ 4382 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4383 { 4384 DM_Plex *mesh = (DM_Plex*) dm->data; 4385 PetscInt *meet[2]; 4386 PetscInt meetSize, i = 0; 4387 PetscInt dof, off, p, c, m; 4388 4389 PetscFunctionBegin; 4390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4391 PetscValidIntPointer(points, 3); 4392 PetscValidIntPointer(numCoveringPoints, 4); 4393 PetscValidPointer(coveringPoints, 5); 4394 PetscCall(DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0])); 4395 PetscCall(DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1])); 4396 /* Copy in cone of first point */ 4397 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4398 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4399 for (meetSize = 0; meetSize < dof; ++meetSize) { 4400 meet[i][meetSize] = mesh->cones[off+meetSize]; 4401 } 4402 /* Check each successive cone */ 4403 for (p = 1; p < numPoints; ++p) { 4404 PetscInt newMeetSize = 0; 4405 4406 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4407 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4408 for (c = 0; c < dof; ++c) { 4409 const PetscInt point = mesh->cones[off+c]; 4410 4411 for (m = 0; m < meetSize; ++m) { 4412 if (point == meet[i][m]) { 4413 meet[1-i][newMeetSize++] = point; 4414 break; 4415 } 4416 } 4417 } 4418 meetSize = newMeetSize; 4419 i = 1-i; 4420 } 4421 *numCoveringPoints = meetSize; 4422 *coveringPoints = meet[i]; 4423 PetscCall(DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i])); 4424 PetscFunctionReturn(0); 4425 } 4426 4427 /*@C 4428 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4429 4430 Not Collective 4431 4432 Input Parameters: 4433 + dm - The DMPlex object 4434 . numPoints - The number of input points for the meet 4435 - points - The input points 4436 4437 Output Parameters: 4438 + numCoveredPoints - The number of points in the meet 4439 - coveredPoints - The points in the meet 4440 4441 Level: intermediate 4442 4443 Fortran Notes: 4444 Since it returns an array, this routine is only available in Fortran 90, and you must 4445 include petsc.h90 in your code. 4446 4447 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4448 4449 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 4450 @*/ 4451 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4452 { 4453 PetscFunctionBegin; 4454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4455 if (points) PetscValidIntPointer(points,3); 4456 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4457 PetscValidPointer(coveredPoints,5); 4458 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4459 if (numCoveredPoints) *numCoveredPoints = 0; 4460 PetscFunctionReturn(0); 4461 } 4462 4463 /*@C 4464 DMPlexGetFullMeet - Get an array for the meet of the set of points 4465 4466 Not Collective 4467 4468 Input Parameters: 4469 + dm - The DMPlex object 4470 . numPoints - The number of input points for the meet 4471 - points - The input points 4472 4473 Output Parameters: 4474 + numCoveredPoints - The number of points in the meet 4475 - coveredPoints - The points in the meet 4476 4477 Level: intermediate 4478 4479 Fortran Notes: 4480 Since it returns an array, this routine is only available in Fortran 90, and you must 4481 include petsc.h90 in your code. 4482 4483 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4484 4485 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 4486 @*/ 4487 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4488 { 4489 DM_Plex *mesh = (DM_Plex*) dm->data; 4490 PetscInt *offsets, **closures; 4491 PetscInt *meet[2]; 4492 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4493 PetscInt p, h, c, m, mc; 4494 4495 PetscFunctionBegin; 4496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4497 PetscValidIntPointer(points, 3); 4498 PetscValidIntPointer(numCoveredPoints, 4); 4499 PetscValidPointer(coveredPoints, 5); 4500 4501 PetscCall(DMPlexGetDepth(dm, &height)); 4502 PetscCall(PetscMalloc1(numPoints, &closures)); 4503 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4504 mc = mesh->maxConeSize; 4505 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4506 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4507 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4508 4509 for (p = 0; p < numPoints; ++p) { 4510 PetscInt closureSize; 4511 4512 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4513 4514 offsets[p*(height+2)+0] = 0; 4515 for (h = 0; h < height+1; ++h) { 4516 PetscInt pStart, pEnd, i; 4517 4518 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4519 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4520 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4521 offsets[p*(height+2)+h+1] = i; 4522 break; 4523 } 4524 } 4525 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4526 } 4527 PetscCheckFalse(offsets[p*(height+2)+height+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize); 4528 } 4529 for (h = 0; h < height+1; ++h) { 4530 PetscInt dof; 4531 4532 /* Copy in cone of first point */ 4533 dof = offsets[h+1] - offsets[h]; 4534 for (meetSize = 0; meetSize < dof; ++meetSize) { 4535 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4536 } 4537 /* Check each successive cone */ 4538 for (p = 1; p < numPoints && meetSize; ++p) { 4539 PetscInt newMeetSize = 0; 4540 4541 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4542 for (c = 0; c < dof; ++c) { 4543 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4544 4545 for (m = 0; m < meetSize; ++m) { 4546 if (point == meet[i][m]) { 4547 meet[1-i][newMeetSize++] = point; 4548 break; 4549 } 4550 } 4551 } 4552 meetSize = newMeetSize; 4553 i = 1-i; 4554 } 4555 if (meetSize) break; 4556 } 4557 *numCoveredPoints = meetSize; 4558 *coveredPoints = meet[i]; 4559 for (p = 0; p < numPoints; ++p) { 4560 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4561 } 4562 PetscCall(PetscFree(closures)); 4563 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4564 PetscCall(DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i])); 4565 PetscFunctionReturn(0); 4566 } 4567 4568 /*@C 4569 DMPlexEqual - Determine if two DMs have the same topology 4570 4571 Not Collective 4572 4573 Input Parameters: 4574 + dmA - A DMPlex object 4575 - dmB - A DMPlex object 4576 4577 Output Parameters: 4578 . equal - PETSC_TRUE if the topologies are identical 4579 4580 Level: intermediate 4581 4582 Notes: 4583 We are not solving graph isomorphism, so we do not permutation. 4584 4585 .seealso: DMPlexGetCone() 4586 @*/ 4587 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4588 { 4589 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4590 4591 PetscFunctionBegin; 4592 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4593 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4594 PetscValidBoolPointer(equal, 3); 4595 4596 *equal = PETSC_FALSE; 4597 PetscCall(DMPlexGetDepth(dmA, &depth)); 4598 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4599 if (depth != depthB) PetscFunctionReturn(0); 4600 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4601 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4602 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4603 for (p = pStart; p < pEnd; ++p) { 4604 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4605 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4606 4607 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4608 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4609 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4610 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4611 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4612 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4613 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4614 for (c = 0; c < coneSize; ++c) { 4615 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4616 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4617 } 4618 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4619 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4620 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4621 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4622 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4623 for (s = 0; s < supportSize; ++s) { 4624 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4625 } 4626 } 4627 *equal = PETSC_TRUE; 4628 PetscFunctionReturn(0); 4629 } 4630 4631 /*@C 4632 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4633 4634 Not Collective 4635 4636 Input Parameters: 4637 + dm - The DMPlex 4638 . cellDim - The cell dimension 4639 - numCorners - The number of vertices on a cell 4640 4641 Output Parameters: 4642 . numFaceVertices - The number of vertices on a face 4643 4644 Level: developer 4645 4646 Notes: 4647 Of course this can only work for a restricted set of symmetric shapes 4648 4649 .seealso: DMPlexGetCone() 4650 @*/ 4651 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4652 { 4653 MPI_Comm comm; 4654 4655 PetscFunctionBegin; 4656 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4657 PetscValidIntPointer(numFaceVertices,4); 4658 switch (cellDim) { 4659 case 0: 4660 *numFaceVertices = 0; 4661 break; 4662 case 1: 4663 *numFaceVertices = 1; 4664 break; 4665 case 2: 4666 switch (numCorners) { 4667 case 3: /* triangle */ 4668 *numFaceVertices = 2; /* Edge has 2 vertices */ 4669 break; 4670 case 4: /* quadrilateral */ 4671 *numFaceVertices = 2; /* Edge has 2 vertices */ 4672 break; 4673 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4674 *numFaceVertices = 3; /* Edge has 3 vertices */ 4675 break; 4676 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4677 *numFaceVertices = 3; /* Edge has 3 vertices */ 4678 break; 4679 default: 4680 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 4681 } 4682 break; 4683 case 3: 4684 switch (numCorners) { 4685 case 4: /* tetradehdron */ 4686 *numFaceVertices = 3; /* Face has 3 vertices */ 4687 break; 4688 case 6: /* tet cohesive cells */ 4689 *numFaceVertices = 4; /* Face has 4 vertices */ 4690 break; 4691 case 8: /* hexahedron */ 4692 *numFaceVertices = 4; /* Face has 4 vertices */ 4693 break; 4694 case 9: /* tet cohesive Lagrange cells */ 4695 *numFaceVertices = 6; /* Face has 6 vertices */ 4696 break; 4697 case 10: /* quadratic tetrahedron */ 4698 *numFaceVertices = 6; /* Face has 6 vertices */ 4699 break; 4700 case 12: /* hex cohesive Lagrange cells */ 4701 *numFaceVertices = 6; /* Face has 6 vertices */ 4702 break; 4703 case 18: /* quadratic tet cohesive Lagrange cells */ 4704 *numFaceVertices = 6; /* Face has 6 vertices */ 4705 break; 4706 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4707 *numFaceVertices = 9; /* Face has 9 vertices */ 4708 break; 4709 default: 4710 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 4711 } 4712 break; 4713 default: 4714 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim); 4715 } 4716 PetscFunctionReturn(0); 4717 } 4718 4719 /*@ 4720 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4721 4722 Not Collective 4723 4724 Input Parameter: 4725 . dm - The DMPlex object 4726 4727 Output Parameter: 4728 . depthLabel - The DMLabel recording point depth 4729 4730 Level: developer 4731 4732 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), 4733 @*/ 4734 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4735 { 4736 PetscFunctionBegin; 4737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4738 PetscValidPointer(depthLabel, 2); 4739 *depthLabel = dm->depthLabel; 4740 PetscFunctionReturn(0); 4741 } 4742 4743 /*@ 4744 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4745 4746 Not Collective 4747 4748 Input Parameter: 4749 . dm - The DMPlex object 4750 4751 Output Parameter: 4752 . depth - The number of strata (breadth first levels) in the DAG 4753 4754 Level: developer 4755 4756 Notes: 4757 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4758 The point depth is described more in detail in DMPlexGetDepthStratum(). 4759 An empty mesh gives -1. 4760 4761 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize() 4762 @*/ 4763 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4764 { 4765 DMLabel label; 4766 PetscInt d = 0; 4767 4768 PetscFunctionBegin; 4769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4770 PetscValidIntPointer(depth, 2); 4771 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4772 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4773 *depth = d-1; 4774 PetscFunctionReturn(0); 4775 } 4776 4777 /*@ 4778 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4779 4780 Not Collective 4781 4782 Input Parameters: 4783 + dm - The DMPlex object 4784 - stratumValue - The requested depth 4785 4786 Output Parameters: 4787 + start - The first point at this depth 4788 - end - One beyond the last point at this depth 4789 4790 Notes: 4791 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4792 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4793 higher dimension, e.g., "edges". 4794 4795 Level: developer 4796 4797 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate() 4798 @*/ 4799 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4800 { 4801 DMLabel label; 4802 PetscInt pStart, pEnd; 4803 4804 PetscFunctionBegin; 4805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4806 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4807 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4808 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4809 if (pStart == pEnd) PetscFunctionReturn(0); 4810 if (stratumValue < 0) { 4811 if (start) *start = pStart; 4812 if (end) *end = pEnd; 4813 PetscFunctionReturn(0); 4814 } 4815 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4816 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4817 PetscCall(DMLabelGetStratumBounds(label, stratumValue, start, end)); 4818 PetscFunctionReturn(0); 4819 } 4820 4821 /*@ 4822 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4823 4824 Not Collective 4825 4826 Input Parameters: 4827 + dm - The DMPlex object 4828 - stratumValue - The requested height 4829 4830 Output Parameters: 4831 + start - The first point at this height 4832 - end - One beyond the last point at this height 4833 4834 Notes: 4835 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4836 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4837 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4838 4839 Level: developer 4840 4841 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight() 4842 @*/ 4843 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4844 { 4845 DMLabel label; 4846 PetscInt depth, pStart, pEnd; 4847 4848 PetscFunctionBegin; 4849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4850 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4851 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4852 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4853 if (pStart == pEnd) PetscFunctionReturn(0); 4854 if (stratumValue < 0) { 4855 if (start) *start = pStart; 4856 if (end) *end = pEnd; 4857 PetscFunctionReturn(0); 4858 } 4859 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4860 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4861 PetscCall(DMLabelGetNumValues(label, &depth)); 4862 PetscCall(DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end)); 4863 PetscFunctionReturn(0); 4864 } 4865 4866 /*@ 4867 DMPlexGetPointDepth - Get the depth of a given point 4868 4869 Not Collective 4870 4871 Input Parameters: 4872 + dm - The DMPlex object 4873 - point - The point 4874 4875 Output Parameter: 4876 . depth - The depth of the point 4877 4878 Level: intermediate 4879 4880 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight() 4881 @*/ 4882 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4883 { 4884 PetscFunctionBegin; 4885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4886 PetscValidIntPointer(depth, 3); 4887 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4888 PetscFunctionReturn(0); 4889 } 4890 4891 /*@ 4892 DMPlexGetPointHeight - Get the height of a given point 4893 4894 Not Collective 4895 4896 Input Parameters: 4897 + dm - The DMPlex object 4898 - point - The point 4899 4900 Output Parameter: 4901 . height - The height of the point 4902 4903 Level: intermediate 4904 4905 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth() 4906 @*/ 4907 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4908 { 4909 PetscInt n, pDepth; 4910 4911 PetscFunctionBegin; 4912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4913 PetscValidIntPointer(height, 3); 4914 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4915 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4916 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4917 PetscFunctionReturn(0); 4918 } 4919 4920 /*@ 4921 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4922 4923 Not Collective 4924 4925 Input Parameter: 4926 . dm - The DMPlex object 4927 4928 Output Parameter: 4929 . celltypeLabel - The DMLabel recording cell polytope type 4930 4931 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4932 DMCreateLabel(dm, "celltype") beforehand. 4933 4934 Level: developer 4935 4936 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel() 4937 @*/ 4938 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4939 { 4940 PetscFunctionBegin; 4941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4942 PetscValidPointer(celltypeLabel, 2); 4943 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4944 *celltypeLabel = dm->celltypeLabel; 4945 PetscFunctionReturn(0); 4946 } 4947 4948 /*@ 4949 DMPlexGetCellType - Get the polytope type of a given cell 4950 4951 Not Collective 4952 4953 Input Parameters: 4954 + dm - The DMPlex object 4955 - cell - The cell 4956 4957 Output Parameter: 4958 . celltype - The polytope type of the cell 4959 4960 Level: intermediate 4961 4962 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth() 4963 @*/ 4964 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4965 { 4966 DMLabel label; 4967 PetscInt ct; 4968 4969 PetscFunctionBegin; 4970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4971 PetscValidPointer(celltype, 3); 4972 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4973 PetscCall(DMLabelGetValue(label, cell, &ct)); 4974 PetscCheckFalse(ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell); 4975 *celltype = (DMPolytopeType) ct; 4976 PetscFunctionReturn(0); 4977 } 4978 4979 /*@ 4980 DMPlexSetCellType - Set the polytope type of a given cell 4981 4982 Not Collective 4983 4984 Input Parameters: 4985 + dm - The DMPlex object 4986 . cell - The cell 4987 - celltype - The polytope type of the cell 4988 4989 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4990 is executed. This function will override the computed type. However, if automatic classification will not succeed 4991 and a user wants to manually specify all types, the classification must be disabled by calling 4992 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4993 4994 Level: advanced 4995 4996 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel() 4997 @*/ 4998 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 4999 { 5000 DMLabel label; 5001 5002 PetscFunctionBegin; 5003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5004 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5005 PetscCall(DMLabelSetValue(label, cell, celltype)); 5006 PetscFunctionReturn(0); 5007 } 5008 5009 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5010 { 5011 PetscSection section, s; 5012 Mat m; 5013 PetscInt maxHeight; 5014 5015 PetscFunctionBegin; 5016 PetscCall(DMClone(dm, cdm)); 5017 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5018 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5019 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5020 PetscCall(DMSetLocalSection(*cdm, section)); 5021 PetscCall(PetscSectionDestroy(§ion)); 5022 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5023 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5024 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5025 PetscCall(PetscSectionDestroy(&s)); 5026 PetscCall(MatDestroy(&m)); 5027 5028 PetscCall(DMSetNumFields(*cdm, 1)); 5029 PetscCall(DMCreateDS(*cdm)); 5030 PetscFunctionReturn(0); 5031 } 5032 5033 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5034 { 5035 Vec coordsLocal; 5036 DM coordsDM; 5037 5038 PetscFunctionBegin; 5039 *field = NULL; 5040 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5041 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5042 if (coordsLocal && coordsDM) { 5043 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5044 } 5045 PetscFunctionReturn(0); 5046 } 5047 5048 /*@C 5049 DMPlexGetConeSection - Return a section which describes the layout of cone data 5050 5051 Not Collective 5052 5053 Input Parameters: 5054 . dm - The DMPlex object 5055 5056 Output Parameter: 5057 . section - The PetscSection object 5058 5059 Level: developer 5060 5061 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations() 5062 @*/ 5063 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5064 { 5065 DM_Plex *mesh = (DM_Plex*) dm->data; 5066 5067 PetscFunctionBegin; 5068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5069 if (section) *section = mesh->coneSection; 5070 PetscFunctionReturn(0); 5071 } 5072 5073 /*@C 5074 DMPlexGetSupportSection - Return a section which describes the layout of support data 5075 5076 Not Collective 5077 5078 Input Parameters: 5079 . dm - The DMPlex object 5080 5081 Output Parameter: 5082 . section - The PetscSection object 5083 5084 Level: developer 5085 5086 .seealso: DMPlexGetConeSection() 5087 @*/ 5088 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5089 { 5090 DM_Plex *mesh = (DM_Plex*) dm->data; 5091 5092 PetscFunctionBegin; 5093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5094 if (section) *section = mesh->supportSection; 5095 PetscFunctionReturn(0); 5096 } 5097 5098 /*@C 5099 DMPlexGetCones - Return cone data 5100 5101 Not Collective 5102 5103 Input Parameters: 5104 . dm - The DMPlex object 5105 5106 Output Parameter: 5107 . cones - The cone for each point 5108 5109 Level: developer 5110 5111 .seealso: DMPlexGetConeSection() 5112 @*/ 5113 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5114 { 5115 DM_Plex *mesh = (DM_Plex*) dm->data; 5116 5117 PetscFunctionBegin; 5118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5119 if (cones) *cones = mesh->cones; 5120 PetscFunctionReturn(0); 5121 } 5122 5123 /*@C 5124 DMPlexGetConeOrientations - Return cone orientation data 5125 5126 Not Collective 5127 5128 Input Parameters: 5129 . dm - The DMPlex object 5130 5131 Output Parameter: 5132 . coneOrientations - The array of cone orientations for all points 5133 5134 Level: developer 5135 5136 Notes: 5137 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5138 5139 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5140 5141 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation() 5142 @*/ 5143 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5144 { 5145 DM_Plex *mesh = (DM_Plex*) dm->data; 5146 5147 PetscFunctionBegin; 5148 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5149 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5150 PetscFunctionReturn(0); 5151 } 5152 5153 /******************************** FEM Support **********************************/ 5154 5155 /* 5156 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5157 representing a line in the section. 5158 */ 5159 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5160 { 5161 PetscFunctionBeginHot; 5162 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5163 if (line < 0) { 5164 *k = 0; 5165 *Nc = 0; 5166 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5167 *k = 1; 5168 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5169 /* An order k SEM disc has k-1 dofs on an edge */ 5170 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5171 *k = *k / *Nc + 1; 5172 } 5173 PetscFunctionReturn(0); 5174 } 5175 5176 /*@ 5177 5178 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5179 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5180 section provided (or the section of the DM). 5181 5182 Input Parameters: 5183 + dm - The DM 5184 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5185 - section - The PetscSection to reorder, or NULL for the default section 5186 5187 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5188 degree of the basis. 5189 5190 Example: 5191 A typical interpolated single-quad mesh might order points as 5192 .vb 5193 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5194 5195 v4 -- e6 -- v3 5196 | | 5197 e7 c0 e8 5198 | | 5199 v1 -- e5 -- v2 5200 .ve 5201 5202 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5203 dofs in the order of points, e.g., 5204 .vb 5205 c0 -> [0,1,2,3] 5206 v1 -> [4] 5207 ... 5208 e5 -> [8, 9] 5209 .ve 5210 5211 which corresponds to the dofs 5212 .vb 5213 6 10 11 7 5214 13 2 3 15 5215 12 0 1 14 5216 4 8 9 5 5217 .ve 5218 5219 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5220 .vb 5221 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5222 .ve 5223 5224 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5225 .vb 5226 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5227 .ve 5228 5229 Level: developer 5230 5231 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection() 5232 @*/ 5233 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5234 { 5235 DMLabel label; 5236 PetscInt dim, depth = -1, eStart = -1, Nf; 5237 PetscBool vertexchart; 5238 5239 PetscFunctionBegin; 5240 PetscCall(DMGetDimension(dm, &dim)); 5241 if (dim < 1) PetscFunctionReturn(0); 5242 if (point < 0) { 5243 PetscInt sStart,sEnd; 5244 5245 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5246 point = sEnd-sStart ? sStart : point; 5247 } 5248 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5249 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5250 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5251 if (depth == 1) {eStart = point;} 5252 else if (depth == dim) { 5253 const PetscInt *cone; 5254 5255 PetscCall(DMPlexGetCone(dm, point, &cone)); 5256 if (dim == 2) eStart = cone[0]; 5257 else if (dim == 3) { 5258 const PetscInt *cone2; 5259 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5260 eStart = cone2[0]; 5261 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim); 5262 } else PetscCheckFalse(depth >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %D of depth %D cannot be used to bootstrap spectral ordering for dim %D", point, depth, dim); 5263 { /* Determine whether the chart covers all points or just vertices. */ 5264 PetscInt pStart,pEnd,cStart,cEnd; 5265 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5266 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5267 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5268 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5269 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5270 } 5271 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5272 for (PetscInt d=1; d<=dim; d++) { 5273 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5274 PetscInt *perm; 5275 5276 for (f = 0; f < Nf; ++f) { 5277 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5278 size += PetscPowInt(k+1, d)*Nc; 5279 } 5280 PetscCall(PetscMalloc1(size, &perm)); 5281 for (f = 0; f < Nf; ++f) { 5282 switch (d) { 5283 case 1: 5284 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5285 /* 5286 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5287 We want [ vtx0; edge of length k-1; vtx1 ] 5288 */ 5289 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5290 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5291 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5292 foffset = offset; 5293 break; 5294 case 2: 5295 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5296 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5297 /* The SEM order is 5298 5299 v_lb, {e_b}, v_rb, 5300 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5301 v_lt, reverse {e_t}, v_rt 5302 */ 5303 { 5304 const PetscInt of = 0; 5305 const PetscInt oeb = of + PetscSqr(k-1); 5306 const PetscInt oer = oeb + (k-1); 5307 const PetscInt oet = oer + (k-1); 5308 const PetscInt oel = oet + (k-1); 5309 const PetscInt ovlb = oel + (k-1); 5310 const PetscInt ovrb = ovlb + 1; 5311 const PetscInt ovrt = ovrb + 1; 5312 const PetscInt ovlt = ovrt + 1; 5313 PetscInt o; 5314 5315 /* bottom */ 5316 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5317 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5318 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5319 /* middle */ 5320 for (i = 0; i < k-1; ++i) { 5321 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5322 for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5323 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5324 } 5325 /* top */ 5326 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5327 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5328 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5329 foffset = offset; 5330 } 5331 break; 5332 case 3: 5333 /* The original hex closure is 5334 5335 {c, 5336 f_b, f_t, f_f, f_b, f_r, f_l, 5337 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5338 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5339 */ 5340 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5341 /* The SEM order is 5342 Bottom Slice 5343 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5344 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5345 v_blb, {e_bb}, v_brb, 5346 5347 Middle Slice (j) 5348 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5349 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5350 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5351 5352 Top Slice 5353 v_tlf, {e_tf}, v_trf, 5354 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5355 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5356 */ 5357 { 5358 const PetscInt oc = 0; 5359 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5360 const PetscInt oft = ofb + PetscSqr(k-1); 5361 const PetscInt off = oft + PetscSqr(k-1); 5362 const PetscInt ofk = off + PetscSqr(k-1); 5363 const PetscInt ofr = ofk + PetscSqr(k-1); 5364 const PetscInt ofl = ofr + PetscSqr(k-1); 5365 const PetscInt oebl = ofl + PetscSqr(k-1); 5366 const PetscInt oebb = oebl + (k-1); 5367 const PetscInt oebr = oebb + (k-1); 5368 const PetscInt oebf = oebr + (k-1); 5369 const PetscInt oetf = oebf + (k-1); 5370 const PetscInt oetr = oetf + (k-1); 5371 const PetscInt oetb = oetr + (k-1); 5372 const PetscInt oetl = oetb + (k-1); 5373 const PetscInt oerf = oetl + (k-1); 5374 const PetscInt oelf = oerf + (k-1); 5375 const PetscInt oelb = oelf + (k-1); 5376 const PetscInt oerb = oelb + (k-1); 5377 const PetscInt ovblf = oerb + (k-1); 5378 const PetscInt ovblb = ovblf + 1; 5379 const PetscInt ovbrb = ovblb + 1; 5380 const PetscInt ovbrf = ovbrb + 1; 5381 const PetscInt ovtlf = ovbrf + 1; 5382 const PetscInt ovtrf = ovtlf + 1; 5383 const PetscInt ovtrb = ovtrf + 1; 5384 const PetscInt ovtlb = ovtrb + 1; 5385 PetscInt o, n; 5386 5387 /* Bottom Slice */ 5388 /* bottom */ 5389 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5390 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5391 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5392 /* middle */ 5393 for (i = 0; i < k-1; ++i) { 5394 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5395 for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;} 5396 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5397 } 5398 /* top */ 5399 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5400 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5401 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5402 5403 /* Middle Slice */ 5404 for (j = 0; j < k-1; ++j) { 5405 /* bottom */ 5406 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5407 for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5408 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5409 /* middle */ 5410 for (i = 0; i < k-1; ++i) { 5411 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5412 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset; 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5414 } 5415 /* top */ 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5417 for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5419 } 5420 5421 /* Top Slice */ 5422 /* bottom */ 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5424 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5426 /* middle */ 5427 for (i = 0; i < k-1; ++i) { 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5429 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5431 } 5432 /* top */ 5433 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5434 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5436 5437 foffset = offset; 5438 } 5439 break; 5440 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d); 5441 } 5442 } 5443 PetscCheckFalse(offset != size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size); 5444 /* Check permutation */ 5445 { 5446 PetscInt *check; 5447 5448 PetscCall(PetscMalloc1(size, &check)); 5449 for (i = 0; i < size; ++i) {check[i] = -1; PetscCheckFalse(perm[i] < 0 || perm[i] >= size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);} 5450 for (i = 0; i < size; ++i) check[perm[i]] = i; 5451 for (i = 0; i < size; ++i) {PetscCheckFalse(check[i] < 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);} 5452 PetscCall(PetscFree(check)); 5453 } 5454 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5455 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5456 PetscInt *loc_perm; 5457 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5458 for (PetscInt i=0; i<size; i++) { 5459 loc_perm[i] = perm[i]; 5460 loc_perm[size+i] = size + perm[i]; 5461 } 5462 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5463 } 5464 } 5465 PetscFunctionReturn(0); 5466 } 5467 5468 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5469 { 5470 PetscDS prob; 5471 PetscInt depth, Nf, h; 5472 DMLabel label; 5473 5474 PetscFunctionBeginHot; 5475 PetscCall(DMGetDS(dm, &prob)); 5476 Nf = prob->Nf; 5477 label = dm->depthLabel; 5478 *dspace = NULL; 5479 if (field < Nf) { 5480 PetscObject disc = prob->disc[field]; 5481 5482 if (disc->classid == PETSCFE_CLASSID) { 5483 PetscDualSpace dsp; 5484 5485 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5486 PetscCall(DMLabelGetNumValues(label,&depth)); 5487 PetscCall(DMLabelGetValue(label,point,&h)); 5488 h = depth - 1 - h; 5489 if (h) { 5490 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5491 } else { 5492 *dspace = dsp; 5493 } 5494 } 5495 } 5496 PetscFunctionReturn(0); 5497 } 5498 5499 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5500 { 5501 PetscScalar *array, *vArray; 5502 const PetscInt *cone, *coneO; 5503 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5504 5505 PetscFunctionBeginHot; 5506 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5507 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5508 PetscCall(DMPlexGetCone(dm, point, &cone)); 5509 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5510 if (!values || !*values) { 5511 if ((point >= pStart) && (point < pEnd)) { 5512 PetscInt dof; 5513 5514 PetscCall(PetscSectionGetDof(section, point, &dof)); 5515 size += dof; 5516 } 5517 for (p = 0; p < numPoints; ++p) { 5518 const PetscInt cp = cone[p]; 5519 PetscInt dof; 5520 5521 if ((cp < pStart) || (cp >= pEnd)) continue; 5522 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5523 size += dof; 5524 } 5525 if (!values) { 5526 if (csize) *csize = size; 5527 PetscFunctionReturn(0); 5528 } 5529 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5530 } else { 5531 array = *values; 5532 } 5533 size = 0; 5534 PetscCall(VecGetArray(v, &vArray)); 5535 if ((point >= pStart) && (point < pEnd)) { 5536 PetscInt dof, off, d; 5537 PetscScalar *varr; 5538 5539 PetscCall(PetscSectionGetDof(section, point, &dof)); 5540 PetscCall(PetscSectionGetOffset(section, point, &off)); 5541 varr = &vArray[off]; 5542 for (d = 0; d < dof; ++d, ++offset) { 5543 array[offset] = varr[d]; 5544 } 5545 size += dof; 5546 } 5547 for (p = 0; p < numPoints; ++p) { 5548 const PetscInt cp = cone[p]; 5549 PetscInt o = coneO[p]; 5550 PetscInt dof, off, d; 5551 PetscScalar *varr; 5552 5553 if ((cp < pStart) || (cp >= pEnd)) continue; 5554 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5555 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5556 varr = &vArray[off]; 5557 if (o >= 0) { 5558 for (d = 0; d < dof; ++d, ++offset) { 5559 array[offset] = varr[d]; 5560 } 5561 } else { 5562 for (d = dof-1; d >= 0; --d, ++offset) { 5563 array[offset] = varr[d]; 5564 } 5565 } 5566 size += dof; 5567 } 5568 PetscCall(VecRestoreArray(v, &vArray)); 5569 if (!*values) { 5570 if (csize) *csize = size; 5571 *values = array; 5572 } else { 5573 PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 5574 *csize = size; 5575 } 5576 PetscFunctionReturn(0); 5577 } 5578 5579 /* Compress out points not in the section */ 5580 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5581 { 5582 const PetscInt np = *numPoints; 5583 PetscInt pStart, pEnd, p, q; 5584 5585 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5586 for (p = 0, q = 0; p < np; ++p) { 5587 const PetscInt r = points[p*2]; 5588 if ((r >= pStart) && (r < pEnd)) { 5589 points[q*2] = r; 5590 points[q*2+1] = points[p*2+1]; 5591 ++q; 5592 } 5593 } 5594 *numPoints = q; 5595 return 0; 5596 } 5597 5598 /* Compressed closure does not apply closure permutation */ 5599 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5600 { 5601 const PetscInt *cla = NULL; 5602 PetscInt np, *pts = NULL; 5603 5604 PetscFunctionBeginHot; 5605 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5606 if (*clPoints) { 5607 PetscInt dof, off; 5608 5609 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5610 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5611 PetscCall(ISGetIndices(*clPoints, &cla)); 5612 np = dof/2; 5613 pts = (PetscInt *) &cla[off]; 5614 } else { 5615 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5616 PetscCall(CompressPoints_Private(section, &np, pts)); 5617 } 5618 *numPoints = np; 5619 *points = pts; 5620 *clp = cla; 5621 PetscFunctionReturn(0); 5622 } 5623 5624 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5625 { 5626 PetscFunctionBeginHot; 5627 if (!*clPoints) { 5628 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5629 } else { 5630 PetscCall(ISRestoreIndices(*clPoints, clp)); 5631 } 5632 *numPoints = 0; 5633 *points = NULL; 5634 *clSec = NULL; 5635 *clPoints = NULL; 5636 *clp = NULL; 5637 PetscFunctionReturn(0); 5638 } 5639 5640 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5641 { 5642 PetscInt offset = 0, p; 5643 const PetscInt **perms = NULL; 5644 const PetscScalar **flips = NULL; 5645 5646 PetscFunctionBeginHot; 5647 *size = 0; 5648 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5649 for (p = 0; p < numPoints; p++) { 5650 const PetscInt point = points[2*p]; 5651 const PetscInt *perm = perms ? perms[p] : NULL; 5652 const PetscScalar *flip = flips ? flips[p] : NULL; 5653 PetscInt dof, off, d; 5654 const PetscScalar *varr; 5655 5656 PetscCall(PetscSectionGetDof(section, point, &dof)); 5657 PetscCall(PetscSectionGetOffset(section, point, &off)); 5658 varr = &vArray[off]; 5659 if (clperm) { 5660 if (perm) { 5661 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5662 } else { 5663 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5664 } 5665 if (flip) { 5666 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5667 } 5668 } else { 5669 if (perm) { 5670 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5671 } else { 5672 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5673 } 5674 if (flip) { 5675 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5676 } 5677 } 5678 offset += dof; 5679 } 5680 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5681 *size = offset; 5682 PetscFunctionReturn(0); 5683 } 5684 5685 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5686 { 5687 PetscInt offset = 0, f; 5688 5689 PetscFunctionBeginHot; 5690 *size = 0; 5691 for (f = 0; f < numFields; ++f) { 5692 PetscInt p; 5693 const PetscInt **perms = NULL; 5694 const PetscScalar **flips = NULL; 5695 5696 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5697 for (p = 0; p < numPoints; p++) { 5698 const PetscInt point = points[2*p]; 5699 PetscInt fdof, foff, b; 5700 const PetscScalar *varr; 5701 const PetscInt *perm = perms ? perms[p] : NULL; 5702 const PetscScalar *flip = flips ? flips[p] : NULL; 5703 5704 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5705 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5706 varr = &vArray[foff]; 5707 if (clperm) { 5708 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5709 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5710 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5711 } else { 5712 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5713 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5714 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5715 } 5716 offset += fdof; 5717 } 5718 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5719 } 5720 *size = offset; 5721 PetscFunctionReturn(0); 5722 } 5723 5724 /*@C 5725 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5726 5727 Not collective 5728 5729 Input Parameters: 5730 + dm - The DM 5731 . section - The section describing the layout in v, or NULL to use the default section 5732 . v - The local vector 5733 - point - The point in the DM 5734 5735 Input/Output Parameters: 5736 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5737 - values - An array to use for the values, or NULL to have it allocated automatically; 5738 if the user provided NULL, it is a borrowed array and should not be freed 5739 5740 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5741 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5742 $ assembly function, and a user may already have allocated storage for this operation. 5743 $ 5744 $ A typical use could be 5745 $ 5746 $ values = NULL; 5747 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5748 $ for (cl = 0; cl < clSize; ++cl) { 5749 $ <Compute on closure> 5750 $ } 5751 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5752 $ 5753 $ or 5754 $ 5755 $ PetscMalloc1(clMaxSize, &values); 5756 $ for (p = pStart; p < pEnd; ++p) { 5757 $ clSize = clMaxSize; 5758 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5759 $ for (cl = 0; cl < clSize; ++cl) { 5760 $ <Compute on closure> 5761 $ } 5762 $ } 5763 $ PetscFree(values); 5764 5765 Fortran Notes: 5766 Since it returns an array, this routine is only available in Fortran 90, and you must 5767 include petsc.h90 in your code. 5768 5769 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5770 5771 Level: intermediate 5772 5773 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5774 @*/ 5775 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5776 { 5777 PetscSection clSection; 5778 IS clPoints; 5779 PetscInt *points = NULL; 5780 const PetscInt *clp, *perm; 5781 PetscInt depth, numFields, numPoints, asize; 5782 5783 PetscFunctionBeginHot; 5784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5785 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5786 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5787 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5788 PetscCall(DMPlexGetDepth(dm, &depth)); 5789 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5790 if (depth == 1 && numFields < 2) { 5791 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5792 PetscFunctionReturn(0); 5793 } 5794 /* Get points */ 5795 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5796 /* Get sizes */ 5797 asize = 0; 5798 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5799 PetscInt dof; 5800 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5801 asize += dof; 5802 } 5803 if (values) { 5804 const PetscScalar *vArray; 5805 PetscInt size; 5806 5807 if (*values) { 5808 PetscCheckFalse(*csize < asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %D not sufficient to hold closure size %D", *csize, asize); 5809 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5810 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5811 PetscCall(VecGetArrayRead(v, &vArray)); 5812 /* Get values */ 5813 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5814 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5815 PetscCheckFalse(asize != size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size); 5816 /* Cleanup array */ 5817 PetscCall(VecRestoreArrayRead(v, &vArray)); 5818 } 5819 if (csize) *csize = asize; 5820 /* Cleanup points */ 5821 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5822 PetscFunctionReturn(0); 5823 } 5824 5825 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5826 { 5827 DMLabel depthLabel; 5828 PetscSection clSection; 5829 IS clPoints; 5830 PetscScalar *array; 5831 const PetscScalar *vArray; 5832 PetscInt *points = NULL; 5833 const PetscInt *clp, *perm = NULL; 5834 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5835 5836 PetscFunctionBeginHot; 5837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5838 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5839 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5840 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5841 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5842 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5843 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5844 if (mdepth == 1 && numFields < 2) { 5845 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5846 PetscFunctionReturn(0); 5847 } 5848 /* Get points */ 5849 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5850 for (clsize=0,p=0; p<Np; p++) { 5851 PetscInt dof; 5852 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5853 clsize += dof; 5854 } 5855 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5856 /* Filter points */ 5857 for (p = 0; p < numPoints*2; p += 2) { 5858 PetscInt dep; 5859 5860 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5861 if (dep != depth) continue; 5862 points[Np*2+0] = points[p]; 5863 points[Np*2+1] = points[p+1]; 5864 ++Np; 5865 } 5866 /* Get array */ 5867 if (!values || !*values) { 5868 PetscInt asize = 0, dof; 5869 5870 for (p = 0; p < Np*2; p += 2) { 5871 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5872 asize += dof; 5873 } 5874 if (!values) { 5875 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5876 if (csize) *csize = asize; 5877 PetscFunctionReturn(0); 5878 } 5879 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5880 } else { 5881 array = *values; 5882 } 5883 PetscCall(VecGetArrayRead(v, &vArray)); 5884 /* Get values */ 5885 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5886 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5887 /* Cleanup points */ 5888 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5889 /* Cleanup array */ 5890 PetscCall(VecRestoreArrayRead(v, &vArray)); 5891 if (!*values) { 5892 if (csize) *csize = size; 5893 *values = array; 5894 } else { 5895 PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 5896 *csize = size; 5897 } 5898 PetscFunctionReturn(0); 5899 } 5900 5901 /*@C 5902 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5903 5904 Not collective 5905 5906 Input Parameters: 5907 + dm - The DM 5908 . section - The section describing the layout in v, or NULL to use the default section 5909 . v - The local vector 5910 . point - The point in the DM 5911 . csize - The number of values in the closure, or NULL 5912 - values - The array of values, which is a borrowed array and should not be freed 5913 5914 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5915 5916 Fortran Notes: 5917 Since it returns an array, this routine is only available in Fortran 90, and you must 5918 include petsc.h90 in your code. 5919 5920 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5921 5922 Level: intermediate 5923 5924 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5925 @*/ 5926 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5927 { 5928 PetscInt size = 0; 5929 5930 PetscFunctionBegin; 5931 /* Should work without recalculating size */ 5932 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5933 *values = NULL; 5934 PetscFunctionReturn(0); 5935 } 5936 5937 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5938 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5939 5940 static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 5941 { 5942 PetscInt cdof; /* The number of constraints on this point */ 5943 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5944 PetscScalar *a; 5945 PetscInt off, cind = 0, k; 5946 5947 PetscFunctionBegin; 5948 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5949 PetscCall(PetscSectionGetOffset(section, point, &off)); 5950 a = &array[off]; 5951 if (!cdof || setBC) { 5952 if (clperm) { 5953 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5954 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5955 } else { 5956 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5957 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5958 } 5959 } else { 5960 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5961 if (clperm) { 5962 if (perm) {for (k = 0; k < dof; ++k) { 5963 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5964 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5965 } 5966 } else { 5967 for (k = 0; k < dof; ++k) { 5968 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5969 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5970 } 5971 } 5972 } else { 5973 if (perm) { 5974 for (k = 0; k < dof; ++k) { 5975 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5976 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5977 } 5978 } else { 5979 for (k = 0; k < dof; ++k) { 5980 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5981 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5982 } 5983 } 5984 } 5985 } 5986 PetscFunctionReturn(0); 5987 } 5988 5989 static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 5990 { 5991 PetscInt cdof; /* The number of constraints on this point */ 5992 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5993 PetscScalar *a; 5994 PetscInt off, cind = 0, k; 5995 5996 PetscFunctionBegin; 5997 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5998 PetscCall(PetscSectionGetOffset(section, point, &off)); 5999 a = &array[off]; 6000 if (cdof) { 6001 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6002 if (clperm) { 6003 if (perm) { 6004 for (k = 0; k < dof; ++k) { 6005 if ((cind < cdof) && (k == cdofs[cind])) { 6006 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6007 cind++; 6008 } 6009 } 6010 } else { 6011 for (k = 0; k < dof; ++k) { 6012 if ((cind < cdof) && (k == cdofs[cind])) { 6013 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6014 cind++; 6015 } 6016 } 6017 } 6018 } else { 6019 if (perm) { 6020 for (k = 0; k < dof; ++k) { 6021 if ((cind < cdof) && (k == cdofs[cind])) { 6022 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6023 cind++; 6024 } 6025 } 6026 } else { 6027 for (k = 0; k < dof; ++k) { 6028 if ((cind < cdof) && (k == cdofs[cind])) { 6029 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6030 cind++; 6031 } 6032 } 6033 } 6034 } 6035 } 6036 PetscFunctionReturn(0); 6037 } 6038 6039 static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6040 { 6041 PetscScalar *a; 6042 PetscInt fdof, foff, fcdof, foffset = *offset; 6043 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6044 PetscInt cind = 0, b; 6045 6046 PetscFunctionBegin; 6047 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6048 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6049 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6050 a = &array[foff]; 6051 if (!fcdof || setBC) { 6052 if (clperm) { 6053 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6054 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6055 } else { 6056 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6057 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6058 } 6059 } else { 6060 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6061 if (clperm) { 6062 if (perm) { 6063 for (b = 0; b < fdof; b++) { 6064 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6065 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6066 } 6067 } else { 6068 for (b = 0; b < fdof; b++) { 6069 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6070 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6071 } 6072 } 6073 } else { 6074 if (perm) { 6075 for (b = 0; b < fdof; b++) { 6076 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6077 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6078 } 6079 } else { 6080 for (b = 0; b < fdof; b++) { 6081 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6082 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6083 } 6084 } 6085 } 6086 } 6087 *offset += fdof; 6088 PetscFunctionReturn(0); 6089 } 6090 6091 static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6092 { 6093 PetscScalar *a; 6094 PetscInt fdof, foff, fcdof, foffset = *offset; 6095 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6096 PetscInt Nc, cind = 0, ncind = 0, b; 6097 PetscBool ncSet, fcSet; 6098 6099 PetscFunctionBegin; 6100 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6101 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6102 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6103 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6104 a = &array[foff]; 6105 if (fcdof) { 6106 /* We just override fcdof and fcdofs with Ncc and comps */ 6107 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6108 if (clperm) { 6109 if (perm) { 6110 if (comps) { 6111 for (b = 0; b < fdof; b++) { 6112 ncSet = fcSet = PETSC_FALSE; 6113 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6114 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6115 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6116 } 6117 } else { 6118 for (b = 0; b < fdof; b++) { 6119 if ((cind < fcdof) && (b == fcdofs[cind])) { 6120 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6121 ++cind; 6122 } 6123 } 6124 } 6125 } else { 6126 if (comps) { 6127 for (b = 0; b < fdof; b++) { 6128 ncSet = fcSet = PETSC_FALSE; 6129 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6130 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6131 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6132 } 6133 } else { 6134 for (b = 0; b < fdof; b++) { 6135 if ((cind < fcdof) && (b == fcdofs[cind])) { 6136 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6137 ++cind; 6138 } 6139 } 6140 } 6141 } 6142 } else { 6143 if (perm) { 6144 if (comps) { 6145 for (b = 0; b < fdof; b++) { 6146 ncSet = fcSet = PETSC_FALSE; 6147 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6148 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6149 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6150 } 6151 } else { 6152 for (b = 0; b < fdof; b++) { 6153 if ((cind < fcdof) && (b == fcdofs[cind])) { 6154 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6155 ++cind; 6156 } 6157 } 6158 } 6159 } else { 6160 if (comps) { 6161 for (b = 0; b < fdof; b++) { 6162 ncSet = fcSet = PETSC_FALSE; 6163 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6164 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6165 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6166 } 6167 } else { 6168 for (b = 0; b < fdof; b++) { 6169 if ((cind < fcdof) && (b == fcdofs[cind])) { 6170 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6171 ++cind; 6172 } 6173 } 6174 } 6175 } 6176 } 6177 } 6178 *offset += fdof; 6179 PetscFunctionReturn(0); 6180 } 6181 6182 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6183 { 6184 PetscScalar *array; 6185 const PetscInt *cone, *coneO; 6186 PetscInt pStart, pEnd, p, numPoints, off, dof; 6187 6188 PetscFunctionBeginHot; 6189 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6190 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6191 PetscCall(DMPlexGetCone(dm, point, &cone)); 6192 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6193 PetscCall(VecGetArray(v, &array)); 6194 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6195 const PetscInt cp = !p ? point : cone[p-1]; 6196 const PetscInt o = !p ? 0 : coneO[p-1]; 6197 6198 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6199 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6200 /* ADD_VALUES */ 6201 { 6202 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6203 PetscScalar *a; 6204 PetscInt cdof, coff, cind = 0, k; 6205 6206 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6207 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6208 a = &array[coff]; 6209 if (!cdof) { 6210 if (o >= 0) { 6211 for (k = 0; k < dof; ++k) { 6212 a[k] += values[off+k]; 6213 } 6214 } else { 6215 for (k = 0; k < dof; ++k) { 6216 a[k] += values[off+dof-k-1]; 6217 } 6218 } 6219 } else { 6220 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6221 if (o >= 0) { 6222 for (k = 0; k < dof; ++k) { 6223 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6224 a[k] += values[off+k]; 6225 } 6226 } else { 6227 for (k = 0; k < dof; ++k) { 6228 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6229 a[k] += values[off+dof-k-1]; 6230 } 6231 } 6232 } 6233 } 6234 } 6235 PetscCall(VecRestoreArray(v, &array)); 6236 PetscFunctionReturn(0); 6237 } 6238 6239 /*@C 6240 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6241 6242 Not collective 6243 6244 Input Parameters: 6245 + dm - The DM 6246 . section - The section describing the layout in v, or NULL to use the default section 6247 . v - The local vector 6248 . point - The point in the DM 6249 . values - The array of values 6250 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6251 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6252 6253 Fortran Notes: 6254 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6255 6256 Level: intermediate 6257 6258 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 6259 @*/ 6260 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6261 { 6262 PetscSection clSection; 6263 IS clPoints; 6264 PetscScalar *array; 6265 PetscInt *points = NULL; 6266 const PetscInt *clp, *clperm = NULL; 6267 PetscInt depth, numFields, numPoints, p, clsize; 6268 6269 PetscFunctionBeginHot; 6270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6271 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6272 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6273 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6274 PetscCall(DMPlexGetDepth(dm, &depth)); 6275 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6276 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6277 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6278 PetscFunctionReturn(0); 6279 } 6280 /* Get points */ 6281 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6282 for (clsize=0,p=0; p<numPoints; p++) { 6283 PetscInt dof; 6284 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6285 clsize += dof; 6286 } 6287 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6288 /* Get array */ 6289 PetscCall(VecGetArray(v, &array)); 6290 /* Get values */ 6291 if (numFields > 0) { 6292 PetscInt offset = 0, f; 6293 for (f = 0; f < numFields; ++f) { 6294 const PetscInt **perms = NULL; 6295 const PetscScalar **flips = NULL; 6296 6297 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6298 switch (mode) { 6299 case INSERT_VALUES: 6300 for (p = 0; p < numPoints; p++) { 6301 const PetscInt point = points[2*p]; 6302 const PetscInt *perm = perms ? perms[p] : NULL; 6303 const PetscScalar *flip = flips ? flips[p] : NULL; 6304 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6305 } break; 6306 case INSERT_ALL_VALUES: 6307 for (p = 0; p < numPoints; p++) { 6308 const PetscInt point = points[2*p]; 6309 const PetscInt *perm = perms ? perms[p] : NULL; 6310 const PetscScalar *flip = flips ? flips[p] : NULL; 6311 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6312 } break; 6313 case INSERT_BC_VALUES: 6314 for (p = 0; p < numPoints; p++) { 6315 const PetscInt point = points[2*p]; 6316 const PetscInt *perm = perms ? perms[p] : NULL; 6317 const PetscScalar *flip = flips ? flips[p] : NULL; 6318 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6319 } break; 6320 case ADD_VALUES: 6321 for (p = 0; p < numPoints; p++) { 6322 const PetscInt point = points[2*p]; 6323 const PetscInt *perm = perms ? perms[p] : NULL; 6324 const PetscScalar *flip = flips ? flips[p] : NULL; 6325 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6326 } break; 6327 case ADD_ALL_VALUES: 6328 for (p = 0; p < numPoints; p++) { 6329 const PetscInt point = points[2*p]; 6330 const PetscInt *perm = perms ? perms[p] : NULL; 6331 const PetscScalar *flip = flips ? flips[p] : NULL; 6332 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6333 } break; 6334 case ADD_BC_VALUES: 6335 for (p = 0; p < numPoints; p++) { 6336 const PetscInt point = points[2*p]; 6337 const PetscInt *perm = perms ? perms[p] : NULL; 6338 const PetscScalar *flip = flips ? flips[p] : NULL; 6339 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6340 } break; 6341 default: 6342 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6343 } 6344 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6345 } 6346 } else { 6347 PetscInt dof, off; 6348 const PetscInt **perms = NULL; 6349 const PetscScalar **flips = NULL; 6350 6351 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6352 switch (mode) { 6353 case INSERT_VALUES: 6354 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6355 const PetscInt point = points[2*p]; 6356 const PetscInt *perm = perms ? perms[p] : NULL; 6357 const PetscScalar *flip = flips ? flips[p] : NULL; 6358 PetscCall(PetscSectionGetDof(section, point, &dof)); 6359 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6360 } break; 6361 case INSERT_ALL_VALUES: 6362 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6363 const PetscInt point = points[2*p]; 6364 const PetscInt *perm = perms ? perms[p] : NULL; 6365 const PetscScalar *flip = flips ? flips[p] : NULL; 6366 PetscCall(PetscSectionGetDof(section, point, &dof)); 6367 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6368 } break; 6369 case INSERT_BC_VALUES: 6370 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6371 const PetscInt point = points[2*p]; 6372 const PetscInt *perm = perms ? perms[p] : NULL; 6373 const PetscScalar *flip = flips ? flips[p] : NULL; 6374 PetscCall(PetscSectionGetDof(section, point, &dof)); 6375 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6376 } break; 6377 case ADD_VALUES: 6378 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6379 const PetscInt point = points[2*p]; 6380 const PetscInt *perm = perms ? perms[p] : NULL; 6381 const PetscScalar *flip = flips ? flips[p] : NULL; 6382 PetscCall(PetscSectionGetDof(section, point, &dof)); 6383 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6384 } break; 6385 case ADD_ALL_VALUES: 6386 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6387 const PetscInt point = points[2*p]; 6388 const PetscInt *perm = perms ? perms[p] : NULL; 6389 const PetscScalar *flip = flips ? flips[p] : NULL; 6390 PetscCall(PetscSectionGetDof(section, point, &dof)); 6391 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6392 } break; 6393 case ADD_BC_VALUES: 6394 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6395 const PetscInt point = points[2*p]; 6396 const PetscInt *perm = perms ? perms[p] : NULL; 6397 const PetscScalar *flip = flips ? flips[p] : NULL; 6398 PetscCall(PetscSectionGetDof(section, point, &dof)); 6399 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6400 } break; 6401 default: 6402 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6403 } 6404 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6405 } 6406 /* Cleanup points */ 6407 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6408 /* Cleanup array */ 6409 PetscCall(VecRestoreArray(v, &array)); 6410 PetscFunctionReturn(0); 6411 } 6412 6413 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6414 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6415 { 6416 PetscFunctionBegin; 6417 if (label) { 6418 PetscInt val, fdof; 6419 6420 /* There is a problem with this: 6421 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6422 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6423 Thus I am only going to check val != -1, not val != labelId 6424 */ 6425 PetscCall(DMLabelGetValue(label, point, &val)); 6426 if (val < 0) { 6427 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6428 *offset += fdof; 6429 PetscFunctionReturn(1); 6430 } 6431 } 6432 PetscFunctionReturn(0); 6433 } 6434 6435 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6436 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) 6437 { 6438 PetscSection clSection; 6439 IS clPoints; 6440 PetscScalar *array; 6441 PetscInt *points = NULL; 6442 const PetscInt *clp; 6443 PetscInt numFields, numPoints, p; 6444 PetscInt offset = 0, f; 6445 6446 PetscFunctionBeginHot; 6447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6448 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6449 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6450 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6451 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6452 /* Get points */ 6453 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6454 /* Get array */ 6455 PetscCall(VecGetArray(v, &array)); 6456 /* Get values */ 6457 for (f = 0; f < numFields; ++f) { 6458 const PetscInt **perms = NULL; 6459 const PetscScalar **flips = NULL; 6460 6461 if (!fieldActive[f]) { 6462 for (p = 0; p < numPoints*2; p += 2) { 6463 PetscInt fdof; 6464 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6465 offset += fdof; 6466 } 6467 continue; 6468 } 6469 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6470 switch (mode) { 6471 case INSERT_VALUES: 6472 for (p = 0; p < numPoints; p++) { 6473 const PetscInt point = points[2*p]; 6474 const PetscInt *perm = perms ? perms[p] : NULL; 6475 const PetscScalar *flip = flips ? flips[p] : NULL; 6476 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6477 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6478 } break; 6479 case INSERT_ALL_VALUES: 6480 for (p = 0; p < numPoints; p++) { 6481 const PetscInt point = points[2*p]; 6482 const PetscInt *perm = perms ? perms[p] : NULL; 6483 const PetscScalar *flip = flips ? flips[p] : NULL; 6484 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6485 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6486 } break; 6487 case INSERT_BC_VALUES: 6488 for (p = 0; p < numPoints; p++) { 6489 const PetscInt point = points[2*p]; 6490 const PetscInt *perm = perms ? perms[p] : NULL; 6491 const PetscScalar *flip = flips ? flips[p] : NULL; 6492 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6493 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6494 } break; 6495 case ADD_VALUES: 6496 for (p = 0; p < numPoints; p++) { 6497 const PetscInt point = points[2*p]; 6498 const PetscInt *perm = perms ? perms[p] : NULL; 6499 const PetscScalar *flip = flips ? flips[p] : NULL; 6500 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6501 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6502 } break; 6503 case ADD_ALL_VALUES: 6504 for (p = 0; p < numPoints; p++) { 6505 const PetscInt point = points[2*p]; 6506 const PetscInt *perm = perms ? perms[p] : NULL; 6507 const PetscScalar *flip = flips ? flips[p] : NULL; 6508 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6509 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6510 } break; 6511 default: 6512 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6513 } 6514 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6515 } 6516 /* Cleanup points */ 6517 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6518 /* Cleanup array */ 6519 PetscCall(VecRestoreArray(v, &array)); 6520 PetscFunctionReturn(0); 6521 } 6522 6523 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6524 { 6525 PetscMPIInt rank; 6526 PetscInt i, j; 6527 6528 PetscFunctionBegin; 6529 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6530 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point)); 6531 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i])); 6532 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i])); 6533 numCIndices = numCIndices ? numCIndices : numRIndices; 6534 if (!values) PetscFunctionReturn(0); 6535 for (i = 0; i < numRIndices; i++) { 6536 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6537 for (j = 0; j < numCIndices; j++) { 6538 #if defined(PETSC_USE_COMPLEX) 6539 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6540 #else 6541 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6542 #endif 6543 } 6544 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6545 } 6546 PetscFunctionReturn(0); 6547 } 6548 6549 /* 6550 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6551 6552 Input Parameters: 6553 + section - The section for this data layout 6554 . islocal - Is the section (and thus indices being requested) local or global? 6555 . point - The point contributing dofs with these indices 6556 . off - The global offset of this point 6557 . loff - The local offset of each field 6558 . setBC - The flag determining whether to include indices of boundary values 6559 . perm - A permutation of the dofs on this point, or NULL 6560 - indperm - A permutation of the entire indices array, or NULL 6561 6562 Output Parameter: 6563 . indices - Indices for dofs on this point 6564 6565 Level: developer 6566 6567 Note: The indices could be local or global, depending on the value of 'off'. 6568 */ 6569 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6570 { 6571 PetscInt dof; /* The number of unknowns on this point */ 6572 PetscInt cdof; /* The number of constraints on this point */ 6573 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6574 PetscInt cind = 0, k; 6575 6576 PetscFunctionBegin; 6577 PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6578 PetscCall(PetscSectionGetDof(section, point, &dof)); 6579 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6580 if (!cdof || setBC) { 6581 for (k = 0; k < dof; ++k) { 6582 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6583 const PetscInt ind = indperm ? indperm[preind] : preind; 6584 6585 indices[ind] = off + k; 6586 } 6587 } else { 6588 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6589 for (k = 0; k < dof; ++k) { 6590 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6591 const PetscInt ind = indperm ? indperm[preind] : preind; 6592 6593 if ((cind < cdof) && (k == cdofs[cind])) { 6594 /* Insert check for returning constrained indices */ 6595 indices[ind] = -(off+k+1); 6596 ++cind; 6597 } else { 6598 indices[ind] = off + k - (islocal ? 0 : cind); 6599 } 6600 } 6601 } 6602 *loff += dof; 6603 PetscFunctionReturn(0); 6604 } 6605 6606 /* 6607 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6608 6609 Input Parameters: 6610 + section - a section (global or local) 6611 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6612 . point - point within section 6613 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6614 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6615 . setBC - identify constrained (boundary condition) points via involution. 6616 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6617 . permsoff - offset 6618 - indperm - index permutation 6619 6620 Output Parameter: 6621 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6622 . indices - array to hold indices (as defined by section) of each dof associated with point 6623 6624 Notes: 6625 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6626 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6627 in the local vector. 6628 6629 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6630 significant). It is invalid to call with a global section and setBC=true. 6631 6632 Developer Note: 6633 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6634 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6635 offset could be obtained from the section instead of passing it explicitly as we do now. 6636 6637 Example: 6638 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6639 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6640 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6641 The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign. 6642 6643 Level: developer 6644 */ 6645 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6646 { 6647 PetscInt numFields, foff, f; 6648 6649 PetscFunctionBegin; 6650 PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6651 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6652 for (f = 0, foff = 0; f < numFields; ++f) { 6653 PetscInt fdof, cfdof; 6654 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6655 PetscInt cind = 0, b; 6656 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6657 6658 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6659 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6660 if (!cfdof || setBC) { 6661 for (b = 0; b < fdof; ++b) { 6662 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6663 const PetscInt ind = indperm ? indperm[preind] : preind; 6664 6665 indices[ind] = off+foff+b; 6666 } 6667 } else { 6668 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6669 for (b = 0; b < fdof; ++b) { 6670 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6671 const PetscInt ind = indperm ? indperm[preind] : preind; 6672 6673 if ((cind < cfdof) && (b == fcdofs[cind])) { 6674 indices[ind] = -(off+foff+b+1); 6675 ++cind; 6676 } else { 6677 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6678 } 6679 } 6680 } 6681 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6682 foffs[f] += fdof; 6683 } 6684 PetscFunctionReturn(0); 6685 } 6686 6687 /* 6688 This version believes the globalSection offsets for each field, rather than just the point offset 6689 6690 . foffs - The offset into 'indices' for each field, since it is segregated by field 6691 6692 Notes: 6693 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6694 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6695 */ 6696 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6697 { 6698 PetscInt numFields, foff, f; 6699 6700 PetscFunctionBegin; 6701 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6702 for (f = 0; f < numFields; ++f) { 6703 PetscInt fdof, cfdof; 6704 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6705 PetscInt cind = 0, b; 6706 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6707 6708 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6709 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6710 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6711 if (!cfdof) { 6712 for (b = 0; b < fdof; ++b) { 6713 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6714 const PetscInt ind = indperm ? indperm[preind] : preind; 6715 6716 indices[ind] = foff+b; 6717 } 6718 } else { 6719 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6720 for (b = 0; b < fdof; ++b) { 6721 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6722 const PetscInt ind = indperm ? indperm[preind] : preind; 6723 6724 if ((cind < cfdof) && (b == fcdofs[cind])) { 6725 indices[ind] = -(foff+b+1); 6726 ++cind; 6727 } else { 6728 indices[ind] = foff+b-cind; 6729 } 6730 } 6731 } 6732 foffs[f] += fdof; 6733 } 6734 PetscFunctionReturn(0); 6735 } 6736 6737 PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 6738 { 6739 Mat cMat; 6740 PetscSection aSec, cSec; 6741 IS aIS; 6742 PetscInt aStart = -1, aEnd = -1; 6743 const PetscInt *anchors; 6744 PetscInt numFields, f, p, q, newP = 0; 6745 PetscInt newNumPoints = 0, newNumIndices = 0; 6746 PetscInt *newPoints, *indices, *newIndices; 6747 PetscInt maxAnchor, maxDof; 6748 PetscInt newOffsets[32]; 6749 PetscInt *pointMatOffsets[32]; 6750 PetscInt *newPointOffsets[32]; 6751 PetscScalar *pointMat[32]; 6752 PetscScalar *newValues=NULL,*tmpValues; 6753 PetscBool anyConstrained = PETSC_FALSE; 6754 6755 PetscFunctionBegin; 6756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6757 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6758 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6759 6760 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6761 /* if there are point-to-point constraints */ 6762 if (aSec) { 6763 PetscCall(PetscArrayzero(newOffsets, 32)); 6764 PetscCall(ISGetIndices(aIS,&anchors)); 6765 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6766 /* figure out how many points are going to be in the new element matrix 6767 * (we allow double counting, because it's all just going to be summed 6768 * into the global matrix anyway) */ 6769 for (p = 0; p < 2*numPoints; p+=2) { 6770 PetscInt b = points[p]; 6771 PetscInt bDof = 0, bSecDof; 6772 6773 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6774 if (!bSecDof) { 6775 continue; 6776 } 6777 if (b >= aStart && b < aEnd) { 6778 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6779 } 6780 if (bDof) { 6781 /* this point is constrained */ 6782 /* it is going to be replaced by its anchors */ 6783 PetscInt bOff, q; 6784 6785 anyConstrained = PETSC_TRUE; 6786 newNumPoints += bDof; 6787 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6788 for (q = 0; q < bDof; q++) { 6789 PetscInt a = anchors[bOff + q]; 6790 PetscInt aDof; 6791 6792 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6793 newNumIndices += aDof; 6794 for (f = 0; f < numFields; ++f) { 6795 PetscInt fDof; 6796 6797 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6798 newOffsets[f+1] += fDof; 6799 } 6800 } 6801 } 6802 else { 6803 /* this point is not constrained */ 6804 newNumPoints++; 6805 newNumIndices += bSecDof; 6806 for (f = 0; f < numFields; ++f) { 6807 PetscInt fDof; 6808 6809 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6810 newOffsets[f+1] += fDof; 6811 } 6812 } 6813 } 6814 } 6815 if (!anyConstrained) { 6816 if (outNumPoints) *outNumPoints = 0; 6817 if (outNumIndices) *outNumIndices = 0; 6818 if (outPoints) *outPoints = NULL; 6819 if (outValues) *outValues = NULL; 6820 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6821 PetscFunctionReturn(0); 6822 } 6823 6824 if (outNumPoints) *outNumPoints = newNumPoints; 6825 if (outNumIndices) *outNumIndices = newNumIndices; 6826 6827 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6828 6829 if (!outPoints && !outValues) { 6830 if (offsets) { 6831 for (f = 0; f <= numFields; f++) { 6832 offsets[f] = newOffsets[f]; 6833 } 6834 } 6835 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6836 PetscFunctionReturn(0); 6837 } 6838 6839 PetscCheckFalse(numFields && newOffsets[numFields] != newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices); 6840 6841 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6842 6843 /* workspaces */ 6844 if (numFields) { 6845 for (f = 0; f < numFields; f++) { 6846 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6847 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6848 } 6849 } 6850 else { 6851 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6852 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6853 } 6854 6855 /* get workspaces for the point-to-point matrices */ 6856 if (numFields) { 6857 PetscInt totalOffset, totalMatOffset; 6858 6859 for (p = 0; p < numPoints; p++) { 6860 PetscInt b = points[2*p]; 6861 PetscInt bDof = 0, bSecDof; 6862 6863 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6864 if (!bSecDof) { 6865 for (f = 0; f < numFields; f++) { 6866 newPointOffsets[f][p + 1] = 0; 6867 pointMatOffsets[f][p + 1] = 0; 6868 } 6869 continue; 6870 } 6871 if (b >= aStart && b < aEnd) { 6872 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6873 } 6874 if (bDof) { 6875 for (f = 0; f < numFields; f++) { 6876 PetscInt fDof, q, bOff, allFDof = 0; 6877 6878 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6879 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6880 for (q = 0; q < bDof; q++) { 6881 PetscInt a = anchors[bOff + q]; 6882 PetscInt aFDof; 6883 6884 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6885 allFDof += aFDof; 6886 } 6887 newPointOffsets[f][p+1] = allFDof; 6888 pointMatOffsets[f][p+1] = fDof * allFDof; 6889 } 6890 } 6891 else { 6892 for (f = 0; f < numFields; f++) { 6893 PetscInt fDof; 6894 6895 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6896 newPointOffsets[f][p+1] = fDof; 6897 pointMatOffsets[f][p+1] = 0; 6898 } 6899 } 6900 } 6901 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6902 newPointOffsets[f][0] = totalOffset; 6903 pointMatOffsets[f][0] = totalMatOffset; 6904 for (p = 0; p < numPoints; p++) { 6905 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6906 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6907 } 6908 totalOffset = newPointOffsets[f][numPoints]; 6909 totalMatOffset = pointMatOffsets[f][numPoints]; 6910 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6911 } 6912 } 6913 else { 6914 for (p = 0; p < numPoints; p++) { 6915 PetscInt b = points[2*p]; 6916 PetscInt bDof = 0, bSecDof; 6917 6918 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6919 if (!bSecDof) { 6920 newPointOffsets[0][p + 1] = 0; 6921 pointMatOffsets[0][p + 1] = 0; 6922 continue; 6923 } 6924 if (b >= aStart && b < aEnd) { 6925 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6926 } 6927 if (bDof) { 6928 PetscInt bOff, q, allDof = 0; 6929 6930 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6931 for (q = 0; q < bDof; q++) { 6932 PetscInt a = anchors[bOff + q], aDof; 6933 6934 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6935 allDof += aDof; 6936 } 6937 newPointOffsets[0][p+1] = allDof; 6938 pointMatOffsets[0][p+1] = bSecDof * allDof; 6939 } 6940 else { 6941 newPointOffsets[0][p+1] = bSecDof; 6942 pointMatOffsets[0][p+1] = 0; 6943 } 6944 } 6945 newPointOffsets[0][0] = 0; 6946 pointMatOffsets[0][0] = 0; 6947 for (p = 0; p < numPoints; p++) { 6948 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6949 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6950 } 6951 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6952 } 6953 6954 /* output arrays */ 6955 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6956 6957 /* get the point-to-point matrices; construct newPoints */ 6958 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6959 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6960 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6961 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6962 if (numFields) { 6963 for (p = 0, newP = 0; p < numPoints; p++) { 6964 PetscInt b = points[2*p]; 6965 PetscInt o = points[2*p+1]; 6966 PetscInt bDof = 0, bSecDof; 6967 6968 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6969 if (!bSecDof) { 6970 continue; 6971 } 6972 if (b >= aStart && b < aEnd) { 6973 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6974 } 6975 if (bDof) { 6976 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6977 6978 fStart[0] = 0; 6979 fEnd[0] = 0; 6980 for (f = 0; f < numFields; f++) { 6981 PetscInt fDof; 6982 6983 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6984 fStart[f+1] = fStart[f] + fDof; 6985 fEnd[f+1] = fStart[f+1]; 6986 } 6987 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6988 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6989 6990 fAnchorStart[0] = 0; 6991 fAnchorEnd[0] = 0; 6992 for (f = 0; f < numFields; f++) { 6993 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6994 6995 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 6996 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 6997 } 6998 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6999 for (q = 0; q < bDof; q++) { 7000 PetscInt a = anchors[bOff + q], aOff; 7001 7002 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7003 newPoints[2*(newP + q)] = a; 7004 newPoints[2*(newP + q) + 1] = 0; 7005 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7006 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7007 } 7008 newP += bDof; 7009 7010 if (outValues) { 7011 /* get the point-to-point submatrix */ 7012 for (f = 0; f < numFields; f++) { 7013 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7014 } 7015 } 7016 } 7017 else { 7018 newPoints[2 * newP] = b; 7019 newPoints[2 * newP + 1] = o; 7020 newP++; 7021 } 7022 } 7023 } else { 7024 for (p = 0; p < numPoints; p++) { 7025 PetscInt b = points[2*p]; 7026 PetscInt o = points[2*p+1]; 7027 PetscInt bDof = 0, bSecDof; 7028 7029 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7030 if (!bSecDof) { 7031 continue; 7032 } 7033 if (b >= aStart && b < aEnd) { 7034 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7035 } 7036 if (bDof) { 7037 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7038 7039 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7040 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7041 7042 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7043 for (q = 0; q < bDof; q++) { 7044 PetscInt a = anchors[bOff + q], aOff; 7045 7046 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7047 7048 newPoints[2*(newP + q)] = a; 7049 newPoints[2*(newP + q) + 1] = 0; 7050 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7051 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7052 } 7053 newP += bDof; 7054 7055 /* get the point-to-point submatrix */ 7056 if (outValues) { 7057 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7058 } 7059 } 7060 else { 7061 newPoints[2 * newP] = b; 7062 newPoints[2 * newP + 1] = o; 7063 newP++; 7064 } 7065 } 7066 } 7067 7068 if (outValues) { 7069 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7070 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7071 /* multiply constraints on the right */ 7072 if (numFields) { 7073 for (f = 0; f < numFields; f++) { 7074 PetscInt oldOff = offsets[f]; 7075 7076 for (p = 0; p < numPoints; p++) { 7077 PetscInt cStart = newPointOffsets[f][p]; 7078 PetscInt b = points[2 * p]; 7079 PetscInt c, r, k; 7080 PetscInt dof; 7081 7082 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7083 if (!dof) { 7084 continue; 7085 } 7086 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7087 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7088 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7089 7090 for (r = 0; r < numIndices; r++) { 7091 for (c = 0; c < nCols; c++) { 7092 for (k = 0; k < dof; k++) { 7093 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7094 } 7095 } 7096 } 7097 } 7098 else { 7099 /* copy this column as is */ 7100 for (r = 0; r < numIndices; r++) { 7101 for (c = 0; c < dof; c++) { 7102 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7103 } 7104 } 7105 } 7106 oldOff += dof; 7107 } 7108 } 7109 } 7110 else { 7111 PetscInt oldOff = 0; 7112 for (p = 0; p < numPoints; p++) { 7113 PetscInt cStart = newPointOffsets[0][p]; 7114 PetscInt b = points[2 * p]; 7115 PetscInt c, r, k; 7116 PetscInt dof; 7117 7118 PetscCall(PetscSectionGetDof(section,b,&dof)); 7119 if (!dof) { 7120 continue; 7121 } 7122 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7123 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7124 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7125 7126 for (r = 0; r < numIndices; r++) { 7127 for (c = 0; c < nCols; c++) { 7128 for (k = 0; k < dof; k++) { 7129 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7130 } 7131 } 7132 } 7133 } 7134 else { 7135 /* copy this column as is */ 7136 for (r = 0; r < numIndices; r++) { 7137 for (c = 0; c < dof; c++) { 7138 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7139 } 7140 } 7141 } 7142 oldOff += dof; 7143 } 7144 } 7145 7146 if (multiplyLeft) { 7147 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7148 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7149 /* multiply constraints transpose on the left */ 7150 if (numFields) { 7151 for (f = 0; f < numFields; f++) { 7152 PetscInt oldOff = offsets[f]; 7153 7154 for (p = 0; p < numPoints; p++) { 7155 PetscInt rStart = newPointOffsets[f][p]; 7156 PetscInt b = points[2 * p]; 7157 PetscInt c, r, k; 7158 PetscInt dof; 7159 7160 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7161 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7162 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7163 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7164 7165 for (r = 0; r < nRows; r++) { 7166 for (c = 0; c < newNumIndices; c++) { 7167 for (k = 0; k < dof; k++) { 7168 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7169 } 7170 } 7171 } 7172 } 7173 else { 7174 /* copy this row as is */ 7175 for (r = 0; r < dof; r++) { 7176 for (c = 0; c < newNumIndices; c++) { 7177 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7178 } 7179 } 7180 } 7181 oldOff += dof; 7182 } 7183 } 7184 } 7185 else { 7186 PetscInt oldOff = 0; 7187 7188 for (p = 0; p < numPoints; p++) { 7189 PetscInt rStart = newPointOffsets[0][p]; 7190 PetscInt b = points[2 * p]; 7191 PetscInt c, r, k; 7192 PetscInt dof; 7193 7194 PetscCall(PetscSectionGetDof(section,b,&dof)); 7195 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7196 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7197 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7198 7199 for (r = 0; r < nRows; r++) { 7200 for (c = 0; c < newNumIndices; c++) { 7201 for (k = 0; k < dof; k++) { 7202 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7203 } 7204 } 7205 } 7206 } 7207 else { 7208 /* copy this row as is */ 7209 for (r = 0; r < dof; r++) { 7210 for (c = 0; c < newNumIndices; c++) { 7211 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7212 } 7213 } 7214 } 7215 oldOff += dof; 7216 } 7217 } 7218 7219 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7220 } 7221 else { 7222 newValues = tmpValues; 7223 } 7224 } 7225 7226 /* clean up */ 7227 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7228 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7229 7230 if (numFields) { 7231 for (f = 0; f < numFields; f++) { 7232 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7233 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7234 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7235 } 7236 } 7237 else { 7238 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7239 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7240 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7241 } 7242 PetscCall(ISRestoreIndices(aIS,&anchors)); 7243 7244 /* output */ 7245 if (outPoints) { 7246 *outPoints = newPoints; 7247 } 7248 else { 7249 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7250 } 7251 if (outValues) { 7252 *outValues = newValues; 7253 } 7254 for (f = 0; f <= numFields; f++) { 7255 offsets[f] = newOffsets[f]; 7256 } 7257 PetscFunctionReturn(0); 7258 } 7259 7260 /*@C 7261 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7262 7263 Not collective 7264 7265 Input Parameters: 7266 + dm - The DM 7267 . section - The PetscSection describing the points (a local section) 7268 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7269 . point - The point defining the closure 7270 - useClPerm - Use the closure point permutation if available 7271 7272 Output Parameters: 7273 + numIndices - The number of dof indices in the closure of point with the input sections 7274 . indices - The dof indices 7275 . outOffsets - Array to write the field offsets into, or NULL 7276 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7277 7278 Notes: 7279 Must call DMPlexRestoreClosureIndices() to free allocated memory 7280 7281 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7282 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7283 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7284 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7285 indices (with the above semantics) are implied. 7286 7287 Level: advanced 7288 7289 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 7290 @*/ 7291 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7292 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7293 { 7294 /* Closure ordering */ 7295 PetscSection clSection; 7296 IS clPoints; 7297 const PetscInt *clp; 7298 PetscInt *points; 7299 const PetscInt *clperm = NULL; 7300 /* Dof permutation and sign flips */ 7301 const PetscInt **perms[32] = {NULL}; 7302 const PetscScalar **flips[32] = {NULL}; 7303 PetscScalar *valCopy = NULL; 7304 /* Hanging node constraints */ 7305 PetscInt *pointsC = NULL; 7306 PetscScalar *valuesC = NULL; 7307 PetscInt NclC, NiC; 7308 7309 PetscInt *idx; 7310 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7311 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7312 7313 PetscFunctionBeginHot; 7314 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7315 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7316 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7317 if (numIndices) PetscValidIntPointer(numIndices, 6); 7318 if (indices) PetscValidPointer(indices, 7); 7319 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7320 if (values) PetscValidPointer(values, 9); 7321 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7322 PetscCheckFalse(Nf > 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf); 7323 PetscCall(PetscArrayzero(offsets, 32)); 7324 /* 1) Get points in closure */ 7325 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7326 if (useClPerm) { 7327 PetscInt depth, clsize; 7328 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7329 for (clsize=0,p=0; p<Ncl; p++) { 7330 PetscInt dof; 7331 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7332 clsize += dof; 7333 } 7334 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7335 } 7336 /* 2) Get number of indices on these points and field offsets from section */ 7337 for (p = 0; p < Ncl*2; p += 2) { 7338 PetscInt dof, fdof; 7339 7340 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7341 for (f = 0; f < Nf; ++f) { 7342 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7343 offsets[f+1] += fdof; 7344 } 7345 Ni += dof; 7346 } 7347 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7348 PetscCheckFalse(Nf && offsets[Nf] != Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni); 7349 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7350 for (f = 0; f < PetscMax(1, Nf); ++f) { 7351 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7352 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7353 /* may need to apply sign changes to the element matrix */ 7354 if (values && flips[f]) { 7355 PetscInt foffset = offsets[f]; 7356 7357 for (p = 0; p < Ncl; ++p) { 7358 PetscInt pnt = points[2*p], fdof; 7359 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7360 7361 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7362 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7363 if (flip) { 7364 PetscInt i, j, k; 7365 7366 if (!valCopy) { 7367 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7368 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7369 *values = valCopy; 7370 } 7371 for (i = 0; i < fdof; ++i) { 7372 PetscScalar fval = flip[i]; 7373 7374 for (k = 0; k < Ni; ++k) { 7375 valCopy[Ni * (foffset + i) + k] *= fval; 7376 valCopy[Ni * k + (foffset + i)] *= fval; 7377 } 7378 } 7379 } 7380 foffset += fdof; 7381 } 7382 } 7383 } 7384 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7385 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7386 if (NclC) { 7387 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7388 for (f = 0; f < PetscMax(1, Nf); ++f) { 7389 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7390 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7391 } 7392 for (f = 0; f < PetscMax(1, Nf); ++f) { 7393 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7394 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7395 } 7396 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7397 Ncl = NclC; 7398 Ni = NiC; 7399 points = pointsC; 7400 if (values) *values = valuesC; 7401 } 7402 /* 5) Calculate indices */ 7403 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7404 if (Nf) { 7405 PetscInt idxOff; 7406 PetscBool useFieldOffsets; 7407 7408 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7409 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7410 if (useFieldOffsets) { 7411 for (p = 0; p < Ncl; ++p) { 7412 const PetscInt pnt = points[p*2]; 7413 7414 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7415 } 7416 } else { 7417 for (p = 0; p < Ncl; ++p) { 7418 const PetscInt pnt = points[p*2]; 7419 7420 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7421 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7422 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7423 * global section. */ 7424 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7425 } 7426 } 7427 } else { 7428 PetscInt off = 0, idxOff; 7429 7430 for (p = 0; p < Ncl; ++p) { 7431 const PetscInt pnt = points[p*2]; 7432 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7433 7434 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7435 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7436 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7437 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7438 } 7439 } 7440 /* 6) Cleanup */ 7441 for (f = 0; f < PetscMax(1, Nf); ++f) { 7442 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7443 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7444 } 7445 if (NclC) { 7446 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7447 } else { 7448 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7449 } 7450 7451 if (numIndices) *numIndices = Ni; 7452 if (indices) *indices = idx; 7453 PetscFunctionReturn(0); 7454 } 7455 7456 /*@C 7457 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7458 7459 Not collective 7460 7461 Input Parameters: 7462 + dm - The DM 7463 . section - The PetscSection describing the points (a local section) 7464 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7465 . point - The point defining the closure 7466 - useClPerm - Use the closure point permutation if available 7467 7468 Output Parameters: 7469 + numIndices - The number of dof indices in the closure of point with the input sections 7470 . indices - The dof indices 7471 . outOffsets - Array to write the field offsets into, or NULL 7472 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7473 7474 Notes: 7475 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7476 7477 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7478 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7479 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7480 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7481 indices (with the above semantics) are implied. 7482 7483 Level: advanced 7484 7485 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 7486 @*/ 7487 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7488 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7489 { 7490 PetscFunctionBegin; 7491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7492 PetscValidPointer(indices, 7); 7493 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7494 PetscFunctionReturn(0); 7495 } 7496 7497 /*@C 7498 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7499 7500 Not collective 7501 7502 Input Parameters: 7503 + dm - The DM 7504 . section - The section describing the layout in v, or NULL to use the default section 7505 . globalSection - The section describing the layout in v, or NULL to use the default global section 7506 . A - The matrix 7507 . point - The point in the DM 7508 . values - The array of values 7509 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7510 7511 Fortran Notes: 7512 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7513 7514 Level: intermediate 7515 7516 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7517 @*/ 7518 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7519 { 7520 DM_Plex *mesh = (DM_Plex*) dm->data; 7521 PetscInt *indices; 7522 PetscInt numIndices; 7523 const PetscScalar *valuesOrig = values; 7524 PetscErrorCode ierr; 7525 7526 PetscFunctionBegin; 7527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7528 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7529 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7530 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7531 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7532 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7533 7534 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7535 7536 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7537 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7538 if (ierr) { 7539 PetscMPIInt rank; 7540 7541 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7542 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7543 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7544 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7545 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7546 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7547 } 7548 if (mesh->printFEM > 1) { 7549 PetscInt i; 7550 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7551 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", indices[i])); 7552 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7553 } 7554 7555 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7556 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7557 PetscFunctionReturn(0); 7558 } 7559 7560 /*@C 7561 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7562 7563 Not collective 7564 7565 Input Parameters: 7566 + dmRow - The DM for the row fields 7567 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7568 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7569 . dmCol - The DM for the column fields 7570 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7571 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7572 . A - The matrix 7573 . point - The point in the DMs 7574 . values - The array of values 7575 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7576 7577 Level: intermediate 7578 7579 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7580 @*/ 7581 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7582 { 7583 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7584 PetscInt *indicesRow, *indicesCol; 7585 PetscInt numIndicesRow, numIndicesCol; 7586 const PetscScalar *valuesOrig = values; 7587 PetscErrorCode ierr; 7588 7589 PetscFunctionBegin; 7590 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7591 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7592 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7593 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7594 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7595 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7596 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7597 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7598 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7599 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7600 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7601 7602 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7603 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7604 7605 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7606 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7607 if (ierr) { 7608 PetscMPIInt rank; 7609 7610 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7611 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7612 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7613 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7614 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7615 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7616 PetscCall(ierr); 7617 } 7618 7619 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7620 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7621 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7622 PetscFunctionReturn(0); 7623 } 7624 7625 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7626 { 7627 DM_Plex *mesh = (DM_Plex*) dmf->data; 7628 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7629 PetscInt *cpoints = NULL; 7630 PetscInt *findices, *cindices; 7631 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7632 PetscInt foffsets[32], coffsets[32]; 7633 DMPolytopeType ct; 7634 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7635 PetscErrorCode ierr; 7636 7637 PetscFunctionBegin; 7638 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7639 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7640 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7641 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7642 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7643 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7644 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7645 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7646 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7647 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7648 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7649 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7650 PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7651 PetscCall(PetscArrayzero(foffsets, 32)); 7652 PetscCall(PetscArrayzero(coffsets, 32)); 7653 /* Column indices */ 7654 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7655 maxFPoints = numCPoints; 7656 /* Compress out points not in the section */ 7657 /* TODO: Squeeze out points with 0 dof as well */ 7658 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7659 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7660 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7661 cpoints[q*2] = cpoints[p]; 7662 cpoints[q*2+1] = cpoints[p+1]; 7663 ++q; 7664 } 7665 } 7666 numCPoints = q; 7667 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7668 PetscInt fdof; 7669 7670 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7671 if (!dof) continue; 7672 for (f = 0; f < numFields; ++f) { 7673 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7674 coffsets[f+1] += fdof; 7675 } 7676 numCIndices += dof; 7677 } 7678 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7679 /* Row indices */ 7680 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7681 { 7682 DMPlexTransform tr; 7683 DMPolytopeType *rct; 7684 PetscInt *rsize, *rcone, *rornt, Nt; 7685 7686 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7687 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7688 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7689 numSubcells = rsize[Nt-1]; 7690 PetscCall(DMPlexTransformDestroy(&tr)); 7691 } 7692 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7693 for (r = 0, q = 0; r < numSubcells; ++r) { 7694 /* TODO Map from coarse to fine cells */ 7695 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7696 /* Compress out points not in the section */ 7697 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7698 for (p = 0; p < numFPoints*2; p += 2) { 7699 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7700 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7701 if (!dof) continue; 7702 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7703 if (s < q) continue; 7704 ftotpoints[q*2] = fpoints[p]; 7705 ftotpoints[q*2+1] = fpoints[p+1]; 7706 ++q; 7707 } 7708 } 7709 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7710 } 7711 numFPoints = q; 7712 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7713 PetscInt fdof; 7714 7715 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7716 if (!dof) continue; 7717 for (f = 0; f < numFields; ++f) { 7718 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7719 foffsets[f+1] += fdof; 7720 } 7721 numFIndices += dof; 7722 } 7723 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7724 7725 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7726 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7727 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7728 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7729 if (numFields) { 7730 const PetscInt **permsF[32] = {NULL}; 7731 const PetscInt **permsC[32] = {NULL}; 7732 7733 for (f = 0; f < numFields; f++) { 7734 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7735 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7736 } 7737 for (p = 0; p < numFPoints; p++) { 7738 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7739 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7740 } 7741 for (p = 0; p < numCPoints; p++) { 7742 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7743 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7744 } 7745 for (f = 0; f < numFields; f++) { 7746 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7747 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7748 } 7749 } else { 7750 const PetscInt **permsF = NULL; 7751 const PetscInt **permsC = NULL; 7752 7753 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7754 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7755 for (p = 0, off = 0; p < numFPoints; p++) { 7756 const PetscInt *perm = permsF ? permsF[p] : NULL; 7757 7758 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7759 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7760 } 7761 for (p = 0, off = 0; p < numCPoints; p++) { 7762 const PetscInt *perm = permsC ? permsC[p] : NULL; 7763 7764 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7765 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7766 } 7767 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7768 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7769 } 7770 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7771 /* TODO: flips */ 7772 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7773 if (ierr) { 7774 PetscMPIInt rank; 7775 7776 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7777 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7778 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7779 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7780 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7781 PetscCall(ierr); 7782 } 7783 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7784 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7785 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7786 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7787 PetscFunctionReturn(0); 7788 } 7789 7790 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7791 { 7792 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7793 PetscInt *cpoints = NULL; 7794 PetscInt foffsets[32], coffsets[32]; 7795 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7796 DMPolytopeType ct; 7797 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7798 7799 PetscFunctionBegin; 7800 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7801 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7802 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7803 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7804 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7805 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7806 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7807 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7808 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7809 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7810 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7811 PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7812 PetscCall(PetscArrayzero(foffsets, 32)); 7813 PetscCall(PetscArrayzero(coffsets, 32)); 7814 /* Column indices */ 7815 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7816 maxFPoints = numCPoints; 7817 /* Compress out points not in the section */ 7818 /* TODO: Squeeze out points with 0 dof as well */ 7819 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7820 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7821 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7822 cpoints[q*2] = cpoints[p]; 7823 cpoints[q*2+1] = cpoints[p+1]; 7824 ++q; 7825 } 7826 } 7827 numCPoints = q; 7828 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7829 PetscInt fdof; 7830 7831 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7832 if (!dof) continue; 7833 for (f = 0; f < numFields; ++f) { 7834 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7835 coffsets[f+1] += fdof; 7836 } 7837 numCIndices += dof; 7838 } 7839 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7840 /* Row indices */ 7841 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7842 { 7843 DMPlexTransform tr; 7844 DMPolytopeType *rct; 7845 PetscInt *rsize, *rcone, *rornt, Nt; 7846 7847 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7848 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7849 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7850 numSubcells = rsize[Nt-1]; 7851 PetscCall(DMPlexTransformDestroy(&tr)); 7852 } 7853 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7854 for (r = 0, q = 0; r < numSubcells; ++r) { 7855 /* TODO Map from coarse to fine cells */ 7856 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7857 /* Compress out points not in the section */ 7858 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7859 for (p = 0; p < numFPoints*2; p += 2) { 7860 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7861 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7862 if (!dof) continue; 7863 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7864 if (s < q) continue; 7865 ftotpoints[q*2] = fpoints[p]; 7866 ftotpoints[q*2+1] = fpoints[p+1]; 7867 ++q; 7868 } 7869 } 7870 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7871 } 7872 numFPoints = q; 7873 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7874 PetscInt fdof; 7875 7876 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7877 if (!dof) continue; 7878 for (f = 0; f < numFields; ++f) { 7879 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7880 foffsets[f+1] += fdof; 7881 } 7882 numFIndices += dof; 7883 } 7884 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7885 7886 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7887 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7888 if (numFields) { 7889 const PetscInt **permsF[32] = {NULL}; 7890 const PetscInt **permsC[32] = {NULL}; 7891 7892 for (f = 0; f < numFields; f++) { 7893 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7894 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7895 } 7896 for (p = 0; p < numFPoints; p++) { 7897 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7898 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7899 } 7900 for (p = 0; p < numCPoints; p++) { 7901 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7902 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7903 } 7904 for (f = 0; f < numFields; f++) { 7905 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7906 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7907 } 7908 } else { 7909 const PetscInt **permsF = NULL; 7910 const PetscInt **permsC = NULL; 7911 7912 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7913 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7914 for (p = 0, off = 0; p < numFPoints; p++) { 7915 const PetscInt *perm = permsF ? permsF[p] : NULL; 7916 7917 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7918 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7919 } 7920 for (p = 0, off = 0; p < numCPoints; p++) { 7921 const PetscInt *perm = permsC ? permsC[p] : NULL; 7922 7923 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7924 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7925 } 7926 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7927 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7928 } 7929 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7930 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7931 PetscFunctionReturn(0); 7932 } 7933 7934 /*@C 7935 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7936 7937 Input Parameter: 7938 . dm - The DMPlex object 7939 7940 Output Parameter: 7941 . cellHeight - The height of a cell 7942 7943 Level: developer 7944 7945 .seealso DMPlexSetVTKCellHeight() 7946 @*/ 7947 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7948 { 7949 DM_Plex *mesh = (DM_Plex*) dm->data; 7950 7951 PetscFunctionBegin; 7952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7953 PetscValidIntPointer(cellHeight, 2); 7954 *cellHeight = mesh->vtkCellHeight; 7955 PetscFunctionReturn(0); 7956 } 7957 7958 /*@C 7959 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7960 7961 Input Parameters: 7962 + dm - The DMPlex object 7963 - cellHeight - The height of a cell 7964 7965 Level: developer 7966 7967 .seealso DMPlexGetVTKCellHeight() 7968 @*/ 7969 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7970 { 7971 DM_Plex *mesh = (DM_Plex*) dm->data; 7972 7973 PetscFunctionBegin; 7974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7975 mesh->vtkCellHeight = cellHeight; 7976 PetscFunctionReturn(0); 7977 } 7978 7979 /*@ 7980 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7981 7982 Input Parameter: 7983 . dm - The DMPlex object 7984 7985 Output Parameters: 7986 + gcStart - The first ghost cell, or NULL 7987 - gcEnd - The upper bound on ghost cells, or NULL 7988 7989 Level: advanced 7990 7991 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 7992 @*/ 7993 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7994 { 7995 DMLabel ctLabel; 7996 7997 PetscFunctionBegin; 7998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7999 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8000 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8001 PetscFunctionReturn(0); 8002 } 8003 8004 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8005 { 8006 PetscSection section, globalSection; 8007 PetscInt *numbers, p; 8008 8009 PetscFunctionBegin; 8010 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8011 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8012 for (p = pStart; p < pEnd; ++p) { 8013 PetscCall(PetscSectionSetDof(section, p, 1)); 8014 } 8015 PetscCall(PetscSectionSetUp(section)); 8016 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8017 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8018 for (p = pStart; p < pEnd; ++p) { 8019 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8020 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8021 else numbers[p-pStart] += shift; 8022 } 8023 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8024 if (globalSize) { 8025 PetscLayout layout; 8026 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8027 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8028 PetscCall(PetscLayoutDestroy(&layout)); 8029 } 8030 PetscCall(PetscSectionDestroy(§ion)); 8031 PetscCall(PetscSectionDestroy(&globalSection)); 8032 PetscFunctionReturn(0); 8033 } 8034 8035 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8036 { 8037 PetscInt cellHeight, cStart, cEnd; 8038 8039 PetscFunctionBegin; 8040 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8041 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8042 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8043 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8044 PetscFunctionReturn(0); 8045 } 8046 8047 /*@ 8048 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8049 8050 Input Parameter: 8051 . dm - The DMPlex object 8052 8053 Output Parameter: 8054 . globalCellNumbers - Global cell numbers for all cells on this process 8055 8056 Level: developer 8057 8058 .seealso DMPlexGetVertexNumbering() 8059 @*/ 8060 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8061 { 8062 DM_Plex *mesh = (DM_Plex*) dm->data; 8063 8064 PetscFunctionBegin; 8065 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8066 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8067 *globalCellNumbers = mesh->globalCellNumbers; 8068 PetscFunctionReturn(0); 8069 } 8070 8071 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8072 { 8073 PetscInt vStart, vEnd; 8074 8075 PetscFunctionBegin; 8076 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8077 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8078 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8079 PetscFunctionReturn(0); 8080 } 8081 8082 /*@ 8083 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8084 8085 Input Parameter: 8086 . dm - The DMPlex object 8087 8088 Output Parameter: 8089 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8090 8091 Level: developer 8092 8093 .seealso DMPlexGetCellNumbering() 8094 @*/ 8095 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8096 { 8097 DM_Plex *mesh = (DM_Plex*) dm->data; 8098 8099 PetscFunctionBegin; 8100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8101 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8102 *globalVertexNumbers = mesh->globalVertexNumbers; 8103 PetscFunctionReturn(0); 8104 } 8105 8106 /*@ 8107 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8108 8109 Input Parameter: 8110 . dm - The DMPlex object 8111 8112 Output Parameter: 8113 . globalPointNumbers - Global numbers for all points on this process 8114 8115 Level: developer 8116 8117 .seealso DMPlexGetCellNumbering() 8118 @*/ 8119 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8120 { 8121 IS nums[4]; 8122 PetscInt depths[4], gdepths[4], starts[4]; 8123 PetscInt depth, d, shift = 0; 8124 8125 PetscFunctionBegin; 8126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8127 PetscCall(DMPlexGetDepth(dm, &depth)); 8128 /* For unstratified meshes use dim instead of depth */ 8129 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8130 for (d = 0; d <= depth; ++d) { 8131 PetscInt end; 8132 8133 depths[d] = depth-d; 8134 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8135 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8136 } 8137 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8138 PetscCallMPI(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8139 for (d = 0; d <= depth; ++d) { 8140 PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]); 8141 } 8142 for (d = 0; d <= depth; ++d) { 8143 PetscInt pStart, pEnd, gsize; 8144 8145 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8146 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8147 shift += gsize; 8148 } 8149 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8150 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8151 PetscFunctionReturn(0); 8152 } 8153 8154 /*@ 8155 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8156 8157 Input Parameter: 8158 . dm - The DMPlex object 8159 8160 Output Parameter: 8161 . ranks - The rank field 8162 8163 Options Database Keys: 8164 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8165 8166 Level: intermediate 8167 8168 .seealso: DMView() 8169 @*/ 8170 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8171 { 8172 DM rdm; 8173 PetscFE fe; 8174 PetscScalar *r; 8175 PetscMPIInt rank; 8176 DMPolytopeType ct; 8177 PetscInt dim, cStart, cEnd, c; 8178 PetscBool simplex; 8179 8180 PetscFunctionBeginUser; 8181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8182 PetscValidPointer(ranks, 2); 8183 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8184 PetscCall(DMClone(dm, &rdm)); 8185 PetscCall(DMGetDimension(rdm, &dim)); 8186 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8187 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8188 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8189 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8190 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8191 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8192 PetscCall(PetscFEDestroy(&fe)); 8193 PetscCall(DMCreateDS(rdm)); 8194 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8195 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8196 PetscCall(VecGetArray(*ranks, &r)); 8197 for (c = cStart; c < cEnd; ++c) { 8198 PetscScalar *lr; 8199 8200 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8201 if (lr) *lr = rank; 8202 } 8203 PetscCall(VecRestoreArray(*ranks, &r)); 8204 PetscCall(DMDestroy(&rdm)); 8205 PetscFunctionReturn(0); 8206 } 8207 8208 /*@ 8209 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8210 8211 Input Parameters: 8212 + dm - The DMPlex 8213 - label - The DMLabel 8214 8215 Output Parameter: 8216 . val - The label value field 8217 8218 Options Database Keys: 8219 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8220 8221 Level: intermediate 8222 8223 .seealso: DMView() 8224 @*/ 8225 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8226 { 8227 DM rdm; 8228 PetscFE fe; 8229 PetscScalar *v; 8230 PetscInt dim, cStart, cEnd, c; 8231 8232 PetscFunctionBeginUser; 8233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8234 PetscValidPointer(label, 2); 8235 PetscValidPointer(val, 3); 8236 PetscCall(DMClone(dm, &rdm)); 8237 PetscCall(DMGetDimension(rdm, &dim)); 8238 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8239 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8240 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8241 PetscCall(PetscFEDestroy(&fe)); 8242 PetscCall(DMCreateDS(rdm)); 8243 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8244 PetscCall(DMCreateGlobalVector(rdm, val)); 8245 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8246 PetscCall(VecGetArray(*val, &v)); 8247 for (c = cStart; c < cEnd; ++c) { 8248 PetscScalar *lv; 8249 PetscInt cval; 8250 8251 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8252 PetscCall(DMLabelGetValue(label, c, &cval)); 8253 *lv = cval; 8254 } 8255 PetscCall(VecRestoreArray(*val, &v)); 8256 PetscCall(DMDestroy(&rdm)); 8257 PetscFunctionReturn(0); 8258 } 8259 8260 /*@ 8261 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8262 8263 Input Parameter: 8264 . dm - The DMPlex object 8265 8266 Notes: 8267 This is a useful diagnostic when creating meshes programmatically. 8268 8269 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8270 8271 Level: developer 8272 8273 .seealso: DMCreate(), DMSetFromOptions() 8274 @*/ 8275 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8276 { 8277 PetscSection coneSection, supportSection; 8278 const PetscInt *cone, *support; 8279 PetscInt coneSize, c, supportSize, s; 8280 PetscInt pStart, pEnd, p, pp, csize, ssize; 8281 PetscBool storagecheck = PETSC_TRUE; 8282 8283 PetscFunctionBegin; 8284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8285 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8286 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8287 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8288 /* Check that point p is found in the support of its cone points, and vice versa */ 8289 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8290 for (p = pStart; p < pEnd; ++p) { 8291 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8292 PetscCall(DMPlexGetCone(dm, p, &cone)); 8293 for (c = 0; c < coneSize; ++c) { 8294 PetscBool dup = PETSC_FALSE; 8295 PetscInt d; 8296 for (d = c-1; d >= 0; --d) { 8297 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8298 } 8299 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8300 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8301 for (s = 0; s < supportSize; ++s) { 8302 if (support[s] == p) break; 8303 } 8304 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8305 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p)); 8306 for (s = 0; s < coneSize; ++s) { 8307 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s])); 8308 } 8309 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8310 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c])); 8311 for (s = 0; s < supportSize; ++s) { 8312 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s])); 8313 } 8314 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8315 PetscCheck(!dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]); 8316 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]); 8317 } 8318 } 8319 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8320 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8321 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8322 PetscCall(DMPlexGetSupport(dm, p, &support)); 8323 for (s = 0; s < supportSize; ++s) { 8324 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8325 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8326 for (c = 0; c < coneSize; ++c) { 8327 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8328 if (cone[c] != pp) { c = 0; break; } 8329 if (cone[c] == p) break; 8330 } 8331 if (c >= coneSize) { 8332 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p)); 8333 for (c = 0; c < supportSize; ++c) { 8334 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c])); 8335 } 8336 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8337 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s])); 8338 for (c = 0; c < coneSize; ++c) { 8339 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c])); 8340 } 8341 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8342 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]); 8343 } 8344 } 8345 } 8346 if (storagecheck) { 8347 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8348 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8349 PetscCheckFalse(csize != ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize); 8350 } 8351 PetscFunctionReturn(0); 8352 } 8353 8354 /* 8355 For submeshes with cohesive cells (see DMPlexConstructCohesiveCells()), we allow a special case where some of the boundary of a face (edges and vertices) are not duplicated. We call these special boundary points "unsplit", since the same edge or vertex appears in both copies of the face. These unsplit points throw off our counting, so we have to explicitly account for them here. 8356 */ 8357 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8358 { 8359 DMPolytopeType cct; 8360 PetscInt ptpoints[4]; 8361 const PetscInt *cone, *ccone, *ptcone; 8362 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8363 8364 PetscFunctionBegin; 8365 *unsplit = 0; 8366 switch (ct) { 8367 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8368 ptpoints[npt++] = c; 8369 break; 8370 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8371 PetscCall(DMPlexGetCone(dm, c, &cone)); 8372 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8373 for (cp = 0; cp < coneSize; ++cp) { 8374 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8375 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8376 } 8377 break; 8378 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8379 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8380 PetscCall(DMPlexGetCone(dm, c, &cone)); 8381 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8382 for (cp = 0; cp < coneSize; ++cp) { 8383 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8384 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8385 for (ccp = 0; ccp < cconeSize; ++ccp) { 8386 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8387 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8388 PetscInt p; 8389 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8390 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8391 } 8392 } 8393 } 8394 break; 8395 default: break; 8396 } 8397 for (pt = 0; pt < npt; ++pt) { 8398 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8399 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8400 } 8401 PetscFunctionReturn(0); 8402 } 8403 8404 /*@ 8405 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8406 8407 Input Parameters: 8408 + dm - The DMPlex object 8409 - cellHeight - Normally 0 8410 8411 Notes: 8412 This is a useful diagnostic when creating meshes programmatically. 8413 Currently applicable only to homogeneous simplex or tensor meshes. 8414 8415 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8416 8417 Level: developer 8418 8419 .seealso: DMCreate(), DMSetFromOptions() 8420 @*/ 8421 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8422 { 8423 DMPlexInterpolatedFlag interp; 8424 DMPolytopeType ct; 8425 PetscInt vStart, vEnd, cStart, cEnd, c; 8426 8427 PetscFunctionBegin; 8428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8429 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8430 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8431 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8432 for (c = cStart; c < cEnd; ++c) { 8433 PetscInt *closure = NULL; 8434 PetscInt coneSize, closureSize, cl, Nv = 0; 8435 8436 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8437 PetscCheckFalse((PetscInt) ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c); 8438 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8439 if (interp == DMPLEX_INTERPOLATED_FULL) { 8440 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8441 PetscCheckFalse(coneSize != DMPolytopeTypeGetConeSize(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has cone size %D != %D", c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct)); 8442 } 8443 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8444 for (cl = 0; cl < closureSize*2; cl += 2) { 8445 const PetscInt p = closure[cl]; 8446 if ((p >= vStart) && (p < vEnd)) ++Nv; 8447 } 8448 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8449 /* Special Case: Tensor faces with identified vertices */ 8450 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8451 PetscInt unsplit; 8452 8453 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8454 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8455 } 8456 PetscCheckFalse(Nv != DMPolytopeTypeGetNumVertices(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D vertices != %D", c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct)); 8457 } 8458 PetscFunctionReturn(0); 8459 } 8460 8461 /*@ 8462 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8463 8464 Not Collective 8465 8466 Input Parameters: 8467 + dm - The DMPlex object 8468 - cellHeight - Normally 0 8469 8470 Notes: 8471 This is a useful diagnostic when creating meshes programmatically. 8472 This routine is only relevant for meshes that are fully interpolated across all ranks. 8473 It will error out if a partially interpolated mesh is given on some rank. 8474 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8475 8476 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8477 8478 Level: developer 8479 8480 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 8481 @*/ 8482 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8483 { 8484 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8485 DMPlexInterpolatedFlag interpEnum; 8486 8487 PetscFunctionBegin; 8488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8489 PetscCall(DMPlexIsInterpolated(dm, &interpEnum)); 8490 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8491 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 8492 PetscMPIInt rank; 8493 MPI_Comm comm; 8494 8495 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8496 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8497 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 8498 } 8499 8500 PetscCall(DMGetDimension(dm, &dim)); 8501 PetscCall(DMPlexGetDepth(dm, &depth)); 8502 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8503 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8504 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8505 for (c = cStart; c < cEnd; ++c) { 8506 const PetscInt *cone, *ornt, *faceSizes, *faces; 8507 const DMPolytopeType *faceTypes; 8508 DMPolytopeType ct; 8509 PetscInt numFaces, coneSize, f; 8510 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8511 8512 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8513 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8514 if (unsplit) continue; 8515 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8516 PetscCall(DMPlexGetCone(dm, c, &cone)); 8517 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8518 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8519 for (cl = 0; cl < closureSize*2; cl += 2) { 8520 const PetscInt p = closure[cl]; 8521 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8522 } 8523 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8524 PetscCheckFalse(coneSize != numFaces,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D faces but should have %D", c, DMPolytopeTypes[ct], coneSize, numFaces); 8525 for (f = 0; f < numFaces; ++f) { 8526 DMPolytopeType fct; 8527 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8528 8529 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8530 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8531 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8532 const PetscInt p = fclosure[cl]; 8533 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8534 } 8535 PetscCheckFalse(fnumCorners != faceSizes[f],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D of type %s (cone idx %D) of cell %D of type %s has %D vertices but should have %D", cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]); 8536 for (v = 0; v < fnumCorners; ++v) { 8537 if (fclosure[v] != faces[fOff+v]) { 8538 PetscInt v1; 8539 8540 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8541 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1])); 8542 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8543 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1])); 8544 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8545 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D of type %s (cone idx %d, ornt %D) of cell %D of type %s vertex %D, %D != %D", cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff+v]); 8546 } 8547 } 8548 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8549 fOff += faceSizes[f]; 8550 } 8551 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8552 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8553 } 8554 } 8555 PetscFunctionReturn(0); 8556 } 8557 8558 /*@ 8559 DMPlexCheckGeometry - Check the geometry of mesh cells 8560 8561 Input Parameter: 8562 . dm - The DMPlex object 8563 8564 Notes: 8565 This is a useful diagnostic when creating meshes programmatically. 8566 8567 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8568 8569 Level: developer 8570 8571 .seealso: DMCreate(), DMSetFromOptions() 8572 @*/ 8573 PetscErrorCode DMPlexCheckGeometry(DM dm) 8574 { 8575 Vec coordinates; 8576 PetscReal detJ, J[9], refVol = 1.0; 8577 PetscReal vol; 8578 PetscBool periodic; 8579 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8580 8581 PetscFunctionBegin; 8582 PetscCall(DMGetDimension(dm, &dim)); 8583 PetscCall(DMGetCoordinateDim(dm, &dE)); 8584 if (dim != dE) PetscFunctionReturn(0); 8585 PetscCall(DMPlexGetDepth(dm, &depth)); 8586 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8587 for (d = 0; d < dim; ++d) refVol *= 2.0; 8588 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8589 /* Make sure local coordinates are created, because that step is collective */ 8590 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8591 for (c = cStart; c < cEnd; ++c) { 8592 DMPolytopeType ct; 8593 PetscInt unsplit; 8594 PetscBool ignoreZeroVol = PETSC_FALSE; 8595 8596 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8597 switch (ct) { 8598 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8599 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8600 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8601 ignoreZeroVol = PETSC_TRUE; break; 8602 default: break; 8603 } 8604 switch (ct) { 8605 case DM_POLYTOPE_TRI_PRISM: 8606 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8607 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8608 case DM_POLYTOPE_PYRAMID: 8609 continue; 8610 default: break; 8611 } 8612 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8613 if (unsplit) continue; 8614 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8615 PetscCheckFalse(detJ < -PETSC_SMALL || (detJ <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double) detJ); 8616 PetscCall(PetscInfo(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol)); 8617 if (depth > 1 && !periodic) { 8618 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8619 PetscCheckFalse(vol < -PETSC_SMALL || (vol <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double) vol); 8620 PetscCall(PetscInfo(dm, "Cell %D FVM Volume %g\n", c, (double) vol)); 8621 } 8622 } 8623 PetscFunctionReturn(0); 8624 } 8625 8626 /*@ 8627 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 8628 8629 Input Parameters: 8630 . dm - The DMPlex object 8631 8632 Notes: 8633 This is mainly intended for debugging/testing purposes. 8634 It currently checks only meshes with no partition overlapping. 8635 8636 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8637 8638 Level: developer 8639 8640 .seealso: DMGetPointSF(), DMSetFromOptions() 8641 @*/ 8642 PetscErrorCode DMPlexCheckPointSF(DM dm) 8643 { 8644 PetscSF pointSF; 8645 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 8646 const PetscInt *locals, *rootdegree; 8647 PetscBool distributed; 8648 8649 PetscFunctionBegin; 8650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8651 PetscCall(DMGetPointSF(dm, &pointSF)); 8652 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8653 if (!distributed) PetscFunctionReturn(0); 8654 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8655 if (overlap) { 8656 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping")); 8657 PetscFunctionReturn(0); 8658 } 8659 PetscCheck(pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 8660 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL)); 8661 PetscCheckFalse(nroots < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 8662 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8663 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8664 8665 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 8666 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8667 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8668 for (l = 0; l < nleaves; ++l) { 8669 const PetscInt point = locals[l]; 8670 8671 PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point); 8672 } 8673 8674 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8675 for (l = 0; l < nleaves; ++l) { 8676 const PetscInt point = locals[l]; 8677 const PetscInt *cone; 8678 PetscInt coneSize, c, idx; 8679 8680 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8681 PetscCall(DMPlexGetCone(dm, point, &cone)); 8682 for (c = 0; c < coneSize; ++c) { 8683 if (!rootdegree[cone[c]]) { 8684 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8685 PetscCheckFalse(idx < 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]); 8686 } 8687 } 8688 } 8689 PetscFunctionReturn(0); 8690 } 8691 8692 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight) 8693 { 8694 PetscFunctionBegin; 8695 PetscCall(DMPlexCheckSymmetry(dm)); 8696 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8697 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8698 PetscCall(DMPlexCheckGeometry(dm)); 8699 PetscCall(DMPlexCheckPointSF(dm)); 8700 PetscCall(DMPlexCheckInterfaceCones(dm)); 8701 PetscFunctionReturn(0); 8702 } 8703 8704 typedef struct cell_stats 8705 { 8706 PetscReal min, max, sum, squaresum; 8707 PetscInt count; 8708 } cell_stats_t; 8709 8710 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8711 { 8712 PetscInt i, N = *len; 8713 8714 for (i = 0; i < N; i++) { 8715 cell_stats_t *A = (cell_stats_t *) a; 8716 cell_stats_t *B = (cell_stats_t *) b; 8717 8718 B->min = PetscMin(A->min,B->min); 8719 B->max = PetscMax(A->max,B->max); 8720 B->sum += A->sum; 8721 B->squaresum += A->squaresum; 8722 B->count += A->count; 8723 } 8724 } 8725 8726 /*@ 8727 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8728 8729 Collective on dm 8730 8731 Input Parameters: 8732 + dm - The DMPlex object 8733 . output - If true, statistics will be displayed on stdout 8734 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8735 8736 Notes: 8737 This is mainly intended for debugging/testing purposes. 8738 8739 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8740 8741 Level: developer 8742 8743 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality() 8744 @*/ 8745 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8746 { 8747 DM dmCoarse; 8748 cell_stats_t stats, globalStats; 8749 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8750 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8751 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8752 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8753 PetscMPIInt rank,size; 8754 8755 PetscFunctionBegin; 8756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8757 stats.min = PETSC_MAX_REAL; 8758 stats.max = PETSC_MIN_REAL; 8759 stats.sum = stats.squaresum = 0.; 8760 stats.count = 0; 8761 8762 PetscCallMPI(MPI_Comm_size(comm, &size)); 8763 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8764 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8765 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8766 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8767 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8768 for (c = cStart; c < cEnd; c++) { 8769 PetscInt i; 8770 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8771 8772 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8773 PetscCheckFalse(detJ < 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c); 8774 for (i = 0; i < PetscSqr(cdim); ++i) { 8775 frobJ += J[i] * J[i]; 8776 frobInvJ += invJ[i] * invJ[i]; 8777 } 8778 cond2 = frobJ * frobInvJ; 8779 cond = PetscSqrtReal(cond2); 8780 8781 stats.min = PetscMin(stats.min,cond); 8782 stats.max = PetscMax(stats.max,cond); 8783 stats.sum += cond; 8784 stats.squaresum += cond2; 8785 stats.count++; 8786 if (output && cond > limit) { 8787 PetscSection coordSection; 8788 Vec coordsLocal; 8789 PetscScalar *coords = NULL; 8790 PetscInt Nv, d, clSize, cl, *closure = NULL; 8791 8792 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8793 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8794 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8795 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond)); 8796 for (i = 0; i < Nv/cdim; ++i) { 8797 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %D: (", i)); 8798 for (d = 0; d < cdim; ++d) { 8799 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8800 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8801 } 8802 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8803 } 8804 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8805 for (cl = 0; cl < clSize*2; cl += 2) { 8806 const PetscInt edge = closure[cl]; 8807 8808 if ((edge >= eStart) && (edge < eEnd)) { 8809 PetscReal len; 8810 8811 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8812 PetscCall(PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len)); 8813 } 8814 } 8815 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8816 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8817 } 8818 } 8819 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8820 8821 if (size > 1) { 8822 PetscMPIInt blockLengths[2] = {4,1}; 8823 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8824 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8825 MPI_Op statReduce; 8826 8827 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8828 PetscCallMPI(MPI_Type_commit(&statType)); 8829 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8830 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8831 PetscCallMPI(MPI_Op_free(&statReduce)); 8832 PetscCallMPI(MPI_Type_free(&statType)); 8833 } else { 8834 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8835 } 8836 if (rank == 0) { 8837 count = globalStats.count; 8838 min = globalStats.min; 8839 max = globalStats.max; 8840 mean = globalStats.sum / globalStats.count; 8841 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8842 } 8843 8844 if (output) { 8845 PetscCall(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)); 8846 } 8847 PetscCall(PetscFree2(J,invJ)); 8848 8849 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8850 if (dmCoarse) { 8851 PetscBool isplex; 8852 8853 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8854 if (isplex) { 8855 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8856 } 8857 } 8858 PetscFunctionReturn(0); 8859 } 8860 8861 /*@ 8862 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8863 orthogonal quality below given tolerance. 8864 8865 Collective on dm 8866 8867 Input Parameters: 8868 + dm - The DMPlex object 8869 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8870 - atol - [0, 1] Absolute tolerance for tagging cells. 8871 8872 Output Parameters: 8873 + OrthQual - Vec containing orthogonal quality per cell 8874 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8875 8876 Options Database Keys: 8877 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8878 supported. 8879 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8880 8881 Notes: 8882 Orthogonal quality is given by the following formula: 8883 8884 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8885 8886 Where A_i is the i'th face-normal vector, f_i is the vector from the cell centroid to the i'th face centroid, and c_i 8887 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8888 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8889 calculating the cosine of the angle between these vectors. 8890 8891 Orthogonal quality ranges from 1 (best) to 0 (worst). 8892 8893 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8894 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8895 8896 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8897 8898 Level: intermediate 8899 8900 .seealso: DMPlexCheckCellShape(), DMCreateLabel() 8901 @*/ 8902 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8903 { 8904 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8905 PetscInt *idx; 8906 PetscScalar *oqVals; 8907 const PetscScalar *cellGeomArr, *faceGeomArr; 8908 PetscReal *ci, *fi, *Ai; 8909 MPI_Comm comm; 8910 Vec cellgeom, facegeom; 8911 DM dmFace, dmCell; 8912 IS glob; 8913 ISLocalToGlobalMapping ltog; 8914 PetscViewer vwr; 8915 8916 PetscFunctionBegin; 8917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8918 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8919 PetscValidPointer(OrthQual, 4); 8920 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8921 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8922 PetscCall(DMGetDimension(dm, &nc)); 8923 PetscCheckFalse(nc < 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc); 8924 { 8925 DMPlexInterpolatedFlag interpFlag; 8926 8927 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8928 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8929 PetscMPIInt rank; 8930 8931 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8932 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8933 } 8934 } 8935 if (OrthQualLabel) { 8936 PetscValidPointer(OrthQualLabel, 5); 8937 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8938 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8939 } else {*OrthQualLabel = NULL;} 8940 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8941 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8942 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8943 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8944 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8945 PetscCall(VecCreate(comm, OrthQual)); 8946 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8947 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 8948 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8949 PetscCall(VecSetUp(*OrthQual)); 8950 PetscCall(ISDestroy(&glob)); 8951 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8952 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8953 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8954 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8955 PetscCall(VecGetDM(cellgeom, &dmCell)); 8956 PetscCall(VecGetDM(facegeom, &dmFace)); 8957 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8958 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 8959 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8960 PetscInt cellarr[2], *adj = NULL; 8961 PetscScalar *cArr, *fArr; 8962 PetscReal minvalc = 1.0, minvalf = 1.0; 8963 PetscFVCellGeom *cg; 8964 8965 idx[cellIter] = cell-cStart; 8966 cellarr[0] = cell; 8967 /* Make indexing into cellGeom easier */ 8968 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8969 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8970 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8971 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8972 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 8973 PetscInt i; 8974 const PetscInt neigh = adj[cellneigh]; 8975 PetscReal normci = 0, normfi = 0, normai = 0; 8976 PetscFVCellGeom *cgneigh; 8977 PetscFVFaceGeom *fg; 8978 8979 /* Don't count ourselves in the neighbor list */ 8980 if (neigh == cell) continue; 8981 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8982 cellarr[1] = neigh; 8983 { 8984 PetscInt numcovpts; 8985 const PetscInt *covpts; 8986 8987 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8988 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8989 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8990 } 8991 8992 /* Compute c_i, f_i and their norms */ 8993 for (i = 0; i < nc; i++) { 8994 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8995 fi[i] = fg->centroid[i] - cg->centroid[i]; 8996 Ai[i] = fg->normal[i]; 8997 normci += PetscPowReal(ci[i], 2); 8998 normfi += PetscPowReal(fi[i], 2); 8999 normai += PetscPowReal(Ai[i], 2); 9000 } 9001 normci = PetscSqrtReal(normci); 9002 normfi = PetscSqrtReal(normfi); 9003 normai = PetscSqrtReal(normai); 9004 9005 /* Normalize and compute for each face-cell-normal pair */ 9006 for (i = 0; i < nc; i++) { 9007 ci[i] = ci[i]/normci; 9008 fi[i] = fi[i]/normfi; 9009 Ai[i] = Ai[i]/normai; 9010 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9011 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9012 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9013 } 9014 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9015 minvalc = PetscRealPart(cArr[cellneighiter]); 9016 } 9017 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9018 minvalf = PetscRealPart(fArr[cellneighiter]); 9019 } 9020 } 9021 PetscCall(PetscFree(adj)); 9022 PetscCall(PetscFree2(cArr, fArr)); 9023 /* Defer to cell if they're equal */ 9024 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9025 if (OrthQualLabel) { 9026 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9027 } 9028 } 9029 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9030 PetscCall(VecAssemblyBegin(*OrthQual)); 9031 PetscCall(VecAssemblyEnd(*OrthQual)); 9032 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9033 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9034 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9035 if (OrthQualLabel) { 9036 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9037 } 9038 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9039 PetscCall(PetscViewerDestroy(&vwr)); 9040 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9041 PetscFunctionReturn(0); 9042 } 9043 9044 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9045 * interpolator construction */ 9046 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9047 { 9048 PetscSection section, newSection, gsection; 9049 PetscSF sf; 9050 PetscBool hasConstraints, ghasConstraints; 9051 9052 PetscFunctionBegin; 9053 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9054 PetscValidPointer(odm,2); 9055 PetscCall(DMGetLocalSection(dm, §ion)); 9056 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9057 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9058 if (!ghasConstraints) { 9059 PetscCall(PetscObjectReference((PetscObject)dm)); 9060 *odm = dm; 9061 PetscFunctionReturn(0); 9062 } 9063 PetscCall(DMClone(dm, odm)); 9064 PetscCall(DMCopyFields(dm, *odm)); 9065 PetscCall(DMGetLocalSection(*odm, &newSection)); 9066 PetscCall(DMGetPointSF(*odm, &sf)); 9067 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9068 PetscCall(DMSetGlobalSection(*odm, gsection)); 9069 PetscCall(PetscSectionDestroy(&gsection)); 9070 PetscFunctionReturn(0); 9071 } 9072 9073 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9074 { 9075 DM dmco, dmfo; 9076 Mat interpo; 9077 Vec rscale; 9078 Vec cglobalo, clocal; 9079 Vec fglobal, fglobalo, flocal; 9080 PetscBool regular; 9081 9082 PetscFunctionBegin; 9083 PetscCall(DMGetFullDM(dmc, &dmco)); 9084 PetscCall(DMGetFullDM(dmf, &dmfo)); 9085 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9086 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9087 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9088 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9089 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9090 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9091 PetscCall(VecSet(cglobalo, 0.)); 9092 PetscCall(VecSet(clocal, 0.)); 9093 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9094 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9095 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9096 PetscCall(VecSet(fglobal, 0.)); 9097 PetscCall(VecSet(fglobalo, 0.)); 9098 PetscCall(VecSet(flocal, 0.)); 9099 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9100 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9101 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9102 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9103 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9104 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9105 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9106 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9107 *shift = fglobal; 9108 PetscCall(VecDestroy(&flocal)); 9109 PetscCall(VecDestroy(&fglobalo)); 9110 PetscCall(VecDestroy(&clocal)); 9111 PetscCall(VecDestroy(&cglobalo)); 9112 PetscCall(VecDestroy(&rscale)); 9113 PetscCall(MatDestroy(&interpo)); 9114 PetscCall(DMDestroy(&dmfo)); 9115 PetscCall(DMDestroy(&dmco)); 9116 PetscFunctionReturn(0); 9117 } 9118 9119 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9120 { 9121 PetscObject shifto; 9122 Vec shift; 9123 9124 PetscFunctionBegin; 9125 if (!interp) { 9126 Vec rscale; 9127 9128 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9129 PetscCall(VecDestroy(&rscale)); 9130 } else { 9131 PetscCall(PetscObjectReference((PetscObject)interp)); 9132 } 9133 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9134 if (!shifto) { 9135 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9136 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9137 shifto = (PetscObject) shift; 9138 PetscCall(VecDestroy(&shift)); 9139 } 9140 shift = (Vec) shifto; 9141 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9142 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9143 PetscCall(MatDestroy(&interp)); 9144 PetscFunctionReturn(0); 9145 } 9146 9147 /* Pointwise interpolation 9148 Just code FEM for now 9149 u^f = I u^c 9150 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9151 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9152 I_{ij} = psi^f_i phi^c_j 9153 */ 9154 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9155 { 9156 PetscSection gsc, gsf; 9157 PetscInt m, n; 9158 void *ctx; 9159 DM cdm; 9160 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9161 9162 PetscFunctionBegin; 9163 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9164 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9165 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9166 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9167 9168 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9169 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9170 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9171 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9172 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9173 9174 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9175 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9176 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9177 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9178 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9179 if (scaling) { 9180 /* Use naive scaling */ 9181 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9182 } 9183 PetscFunctionReturn(0); 9184 } 9185 9186 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9187 { 9188 VecScatter ctx; 9189 9190 PetscFunctionBegin; 9191 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9192 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9193 PetscCall(VecScatterDestroy(&ctx)); 9194 PetscFunctionReturn(0); 9195 } 9196 9197 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9198 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9199 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9200 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9201 { 9202 const PetscInt Nc = uOff[1] - uOff[0]; 9203 PetscInt c; 9204 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9205 } 9206 9207 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9208 { 9209 DM dmc; 9210 PetscDS ds; 9211 Vec ones, locmass; 9212 IS cellIS; 9213 PetscFormKey key; 9214 PetscInt depth; 9215 9216 PetscFunctionBegin; 9217 PetscCall(DMClone(dm, &dmc)); 9218 PetscCall(DMCopyDisc(dm, dmc)); 9219 PetscCall(DMGetDS(dmc, &ds)); 9220 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9221 PetscCall(DMCreateGlobalVector(dmc, mass)); 9222 PetscCall(DMGetLocalVector(dmc, &ones)); 9223 PetscCall(DMGetLocalVector(dmc, &locmass)); 9224 PetscCall(DMPlexGetDepth(dmc, &depth)); 9225 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9226 PetscCall(VecSet(locmass, 0.0)); 9227 PetscCall(VecSet(ones, 1.0)); 9228 key.label = NULL; 9229 key.value = 0; 9230 key.field = 0; 9231 key.part = 0; 9232 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9233 PetscCall(ISDestroy(&cellIS)); 9234 PetscCall(VecSet(*mass, 0.0)); 9235 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9236 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9237 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9238 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9239 PetscCall(DMDestroy(&dmc)); 9240 PetscFunctionReturn(0); 9241 } 9242 9243 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9244 { 9245 PetscSection gsc, gsf; 9246 PetscInt m, n; 9247 void *ctx; 9248 DM cdm; 9249 PetscBool regular; 9250 9251 PetscFunctionBegin; 9252 if (dmFine == dmCoarse) { 9253 DM dmc; 9254 PetscDS ds; 9255 PetscWeakForm wf; 9256 Vec u; 9257 IS cellIS; 9258 PetscFormKey key; 9259 PetscInt depth; 9260 9261 PetscCall(DMClone(dmFine, &dmc)); 9262 PetscCall(DMCopyDisc(dmFine, dmc)); 9263 PetscCall(DMGetDS(dmc, &ds)); 9264 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9265 PetscCall(PetscWeakFormClear(wf)); 9266 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9267 PetscCall(DMCreateMatrix(dmc, mass)); 9268 PetscCall(DMGetGlobalVector(dmc, &u)); 9269 PetscCall(DMPlexGetDepth(dmc, &depth)); 9270 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9271 PetscCall(MatZeroEntries(*mass)); 9272 key.label = NULL; 9273 key.value = 0; 9274 key.field = 0; 9275 key.part = 0; 9276 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9277 PetscCall(ISDestroy(&cellIS)); 9278 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9279 PetscCall(DMDestroy(&dmc)); 9280 } else { 9281 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9282 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9283 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9284 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9285 9286 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9287 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9288 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9289 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9290 9291 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9292 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9293 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9294 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9295 } 9296 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9297 PetscFunctionReturn(0); 9298 } 9299 9300 /*@ 9301 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9302 9303 Input Parameter: 9304 . dm - The DMPlex object 9305 9306 Output Parameter: 9307 . regular - The flag 9308 9309 Level: intermediate 9310 9311 .seealso: DMPlexSetRegularRefinement() 9312 @*/ 9313 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9314 { 9315 PetscFunctionBegin; 9316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9317 PetscValidBoolPointer(regular, 2); 9318 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9319 PetscFunctionReturn(0); 9320 } 9321 9322 /*@ 9323 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9324 9325 Input Parameters: 9326 + dm - The DMPlex object 9327 - regular - The flag 9328 9329 Level: intermediate 9330 9331 .seealso: DMPlexGetRegularRefinement() 9332 @*/ 9333 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9334 { 9335 PetscFunctionBegin; 9336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9337 ((DM_Plex *) dm->data)->regularRefinement = regular; 9338 PetscFunctionReturn(0); 9339 } 9340 9341 /* anchors */ 9342 /*@ 9343 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9344 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9345 9346 not collective 9347 9348 Input Parameter: 9349 . dm - The DMPlex object 9350 9351 Output Parameters: 9352 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9353 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9354 9355 Level: intermediate 9356 9357 .seealso: DMPlexSetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9358 @*/ 9359 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9360 { 9361 DM_Plex *plex = (DM_Plex *)dm->data; 9362 9363 PetscFunctionBegin; 9364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9365 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9366 if (anchorSection) *anchorSection = plex->anchorSection; 9367 if (anchorIS) *anchorIS = plex->anchorIS; 9368 PetscFunctionReturn(0); 9369 } 9370 9371 /*@ 9372 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9373 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9374 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9375 9376 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9377 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9378 9379 collective on dm 9380 9381 Input Parameters: 9382 + dm - The DMPlex object 9383 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 9384 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9385 9386 The reference counts of anchorSection and anchorIS are incremented. 9387 9388 Level: intermediate 9389 9390 .seealso: DMPlexGetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9391 @*/ 9392 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9393 { 9394 DM_Plex *plex = (DM_Plex *)dm->data; 9395 PetscMPIInt result; 9396 9397 PetscFunctionBegin; 9398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9399 if (anchorSection) { 9400 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9401 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9402 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9403 } 9404 if (anchorIS) { 9405 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9406 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9407 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9408 } 9409 9410 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9411 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9412 plex->anchorSection = anchorSection; 9413 9414 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9415 PetscCall(ISDestroy(&plex->anchorIS)); 9416 plex->anchorIS = anchorIS; 9417 9418 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9419 PetscInt size, a, pStart, pEnd; 9420 const PetscInt *anchors; 9421 9422 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9423 PetscCall(ISGetLocalSize(anchorIS,&size)); 9424 PetscCall(ISGetIndices(anchorIS,&anchors)); 9425 for (a = 0; a < size; a++) { 9426 PetscInt p; 9427 9428 p = anchors[a]; 9429 if (p >= pStart && p < pEnd) { 9430 PetscInt dof; 9431 9432 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9433 if (dof) { 9434 9435 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9436 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p); 9437 } 9438 } 9439 } 9440 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9441 } 9442 /* reset the generic constraints */ 9443 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9444 PetscFunctionReturn(0); 9445 } 9446 9447 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9448 { 9449 PetscSection anchorSection; 9450 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9451 9452 PetscFunctionBegin; 9453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9454 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9455 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9456 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9457 if (numFields) { 9458 PetscInt f; 9459 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9460 9461 for (f = 0; f < numFields; f++) { 9462 PetscInt numComp; 9463 9464 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9465 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9466 } 9467 } 9468 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9469 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9470 pStart = PetscMax(pStart,sStart); 9471 pEnd = PetscMin(pEnd,sEnd); 9472 pEnd = PetscMax(pStart,pEnd); 9473 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9474 for (p = pStart; p < pEnd; p++) { 9475 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9476 if (dof) { 9477 PetscCall(PetscSectionGetDof(section,p,&dof)); 9478 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9479 for (f = 0; f < numFields; f++) { 9480 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9481 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9482 } 9483 } 9484 } 9485 PetscCall(PetscSectionSetUp(*cSec)); 9486 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9487 PetscFunctionReturn(0); 9488 } 9489 9490 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9491 { 9492 PetscSection aSec; 9493 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9494 const PetscInt *anchors; 9495 PetscInt numFields, f; 9496 IS aIS; 9497 MatType mtype; 9498 PetscBool iscuda,iskokkos; 9499 9500 PetscFunctionBegin; 9501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9502 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9503 PetscCall(PetscSectionGetStorageSize(section, &n)); 9504 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9505 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9506 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9507 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9508 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9509 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9510 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9511 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9512 else mtype = MATSEQAIJ; 9513 PetscCall(MatSetType(*cMat,mtype)); 9514 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9515 PetscCall(ISGetIndices(aIS,&anchors)); 9516 /* cSec will be a subset of aSec and section */ 9517 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9518 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9519 PetscCall(PetscMalloc1(m+1,&i)); 9520 i[0] = 0; 9521 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9522 for (p = pStart; p < pEnd; p++) { 9523 PetscInt rDof, rOff, r; 9524 9525 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9526 if (!rDof) continue; 9527 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9528 if (numFields) { 9529 for (f = 0; f < numFields; f++) { 9530 annz = 0; 9531 for (r = 0; r < rDof; r++) { 9532 a = anchors[rOff + r]; 9533 if (a < sStart || a >= sEnd) continue; 9534 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9535 annz += aDof; 9536 } 9537 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9538 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9539 for (q = 0; q < dof; q++) { 9540 i[off + q + 1] = i[off + q] + annz; 9541 } 9542 } 9543 } else { 9544 annz = 0; 9545 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9546 for (q = 0; q < dof; q++) { 9547 a = anchors[rOff + q]; 9548 if (a < sStart || a >= sEnd) continue; 9549 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9550 annz += aDof; 9551 } 9552 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9553 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9554 for (q = 0; q < dof; q++) { 9555 i[off + q + 1] = i[off + q] + annz; 9556 } 9557 } 9558 } 9559 nnz = i[m]; 9560 PetscCall(PetscMalloc1(nnz,&j)); 9561 offset = 0; 9562 for (p = pStart; p < pEnd; p++) { 9563 if (numFields) { 9564 for (f = 0; f < numFields; f++) { 9565 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9566 for (q = 0; q < dof; q++) { 9567 PetscInt rDof, rOff, r; 9568 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9569 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9570 for (r = 0; r < rDof; r++) { 9571 PetscInt s; 9572 9573 a = anchors[rOff + r]; 9574 if (a < sStart || a >= sEnd) continue; 9575 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9576 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9577 for (s = 0; s < aDof; s++) { 9578 j[offset++] = aOff + s; 9579 } 9580 } 9581 } 9582 } 9583 } else { 9584 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9585 for (q = 0; q < dof; q++) { 9586 PetscInt rDof, rOff, r; 9587 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9588 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9589 for (r = 0; r < rDof; r++) { 9590 PetscInt s; 9591 9592 a = anchors[rOff + r]; 9593 if (a < sStart || a >= sEnd) continue; 9594 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9595 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9596 for (s = 0; s < aDof; s++) { 9597 j[offset++] = aOff + s; 9598 } 9599 } 9600 } 9601 } 9602 } 9603 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9604 PetscCall(PetscFree(i)); 9605 PetscCall(PetscFree(j)); 9606 PetscCall(ISRestoreIndices(aIS,&anchors)); 9607 PetscFunctionReturn(0); 9608 } 9609 9610 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9611 { 9612 DM_Plex *plex = (DM_Plex *)dm->data; 9613 PetscSection anchorSection, section, cSec; 9614 Mat cMat; 9615 9616 PetscFunctionBegin; 9617 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9618 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9619 if (anchorSection) { 9620 PetscInt Nf; 9621 9622 PetscCall(DMGetLocalSection(dm,§ion)); 9623 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9624 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9625 PetscCall(DMGetNumFields(dm,&Nf)); 9626 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9627 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9628 PetscCall(PetscSectionDestroy(&cSec)); 9629 PetscCall(MatDestroy(&cMat)); 9630 } 9631 PetscFunctionReturn(0); 9632 } 9633 9634 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9635 { 9636 IS subis; 9637 PetscSection section, subsection; 9638 9639 PetscFunctionBegin; 9640 PetscCall(DMGetLocalSection(dm, §ion)); 9641 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9642 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9643 /* Create subdomain */ 9644 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9645 /* Create submodel */ 9646 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9647 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9648 PetscCall(DMSetLocalSection(*subdm, subsection)); 9649 PetscCall(PetscSectionDestroy(&subsection)); 9650 PetscCall(DMCopyDisc(dm, *subdm)); 9651 /* Create map from submodel to global model */ 9652 if (is) { 9653 PetscSection sectionGlobal, subsectionGlobal; 9654 IS spIS; 9655 const PetscInt *spmap; 9656 PetscInt *subIndices; 9657 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9658 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9659 9660 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9661 PetscCall(ISGetIndices(spIS, &spmap)); 9662 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9663 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9664 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9665 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9666 for (p = pStart; p < pEnd; ++p) { 9667 PetscInt gdof, pSubSize = 0; 9668 9669 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9670 if (gdof > 0) { 9671 for (f = 0; f < Nf; ++f) { 9672 PetscInt fdof, fcdof; 9673 9674 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9675 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9676 pSubSize += fdof-fcdof; 9677 } 9678 subSize += pSubSize; 9679 if (pSubSize) { 9680 if (bs < 0) { 9681 bs = pSubSize; 9682 } else if (bs != pSubSize) { 9683 /* Layout does not admit a pointwise block size */ 9684 bs = 1; 9685 } 9686 } 9687 } 9688 } 9689 /* Must have same blocksize on all procs (some might have no points) */ 9690 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9691 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9692 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9693 else {bs = bsMinMax[0];} 9694 PetscCall(PetscMalloc1(subSize, &subIndices)); 9695 for (p = pStart; p < pEnd; ++p) { 9696 PetscInt gdof, goff; 9697 9698 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9699 if (gdof > 0) { 9700 const PetscInt point = spmap[p]; 9701 9702 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9703 for (f = 0; f < Nf; ++f) { 9704 PetscInt fdof, fcdof, fc, f2, poff = 0; 9705 9706 /* Can get rid of this loop by storing field information in the global section */ 9707 for (f2 = 0; f2 < f; ++f2) { 9708 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9709 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9710 poff += fdof-fcdof; 9711 } 9712 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9713 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9714 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9715 subIndices[subOff] = goff+poff+fc; 9716 } 9717 } 9718 } 9719 } 9720 PetscCall(ISRestoreIndices(spIS, &spmap)); 9721 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9722 if (bs > 1) { 9723 /* We need to check that the block size does not come from non-contiguous fields */ 9724 PetscInt i, j, set = 1; 9725 for (i = 0; i < subSize; i += bs) { 9726 for (j = 0; j < bs; ++j) { 9727 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9728 } 9729 } 9730 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9731 } 9732 /* Attach nullspace */ 9733 for (f = 0; f < Nf; ++f) { 9734 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9735 if ((*subdm)->nullspaceConstructors[f]) break; 9736 } 9737 if (f < Nf) { 9738 MatNullSpace nullSpace; 9739 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9740 9741 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9742 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9743 } 9744 } 9745 PetscFunctionReturn(0); 9746 } 9747 9748 /*@ 9749 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9750 9751 Input Parameter: 9752 - dm - The DM 9753 9754 Level: developer 9755 9756 Options Database Keys: 9757 . -dm_plex_monitor_throughput - Activate the monitor 9758 9759 .seealso: DMSetFromOptions(), DMPlexCreate() 9760 @*/ 9761 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9762 { 9763 #if defined(PETSC_USE_LOG) 9764 PetscStageLog stageLog; 9765 PetscLogEvent event; 9766 PetscLogStage stage; 9767 PetscEventPerfInfo eventInfo; 9768 PetscReal cellRate, flopRate; 9769 PetscInt cStart, cEnd, Nf, N; 9770 const char *name; 9771 #endif 9772 9773 PetscFunctionBegin; 9774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9775 #if defined(PETSC_USE_LOG) 9776 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9777 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9778 PetscCall(DMGetNumFields(dm, &Nf)); 9779 PetscCall(PetscLogGetStageLog(&stageLog)); 9780 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9781 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9782 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9783 N = (cEnd - cStart)*Nf*eventInfo.count; 9784 flopRate = eventInfo.flops/eventInfo.time; 9785 cellRate = N/eventInfo.time; 9786 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %D integrals %D reps\n Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double) cellRate, (double) (flopRate/1.e6))); 9787 #else 9788 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9789 #endif 9790 PetscFunctionReturn(0); 9791 } 9792