1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 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; 14 PetscLogEvent DMPLEX_RebalBuildGraph,DMPLEX_RebalRewriteSF,DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 42 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 43 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 44 PetscFunctionReturn(0); 45 } 46 47 /*@ 48 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 49 50 Input Parameters: 51 + dm - The DMPlex object 52 - height - The cell height in the Plex, 0 is the default 53 54 Output Parameters: 55 + cStart - The first "normal" cell 56 - cEnd - The upper bound on "normal"" cells 57 58 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 59 60 Level: developer 61 62 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 63 @*/ 64 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 65 { 66 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 67 PetscInt cS, cE, c; 68 69 PetscFunctionBegin; 70 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 71 for (c = cS; c < cE; ++c) { 72 DMPolytopeType cct; 73 74 PetscCall(DMPlexGetCellType(dm, c, &cct)); 75 if ((PetscInt) cct < 0) break; 76 switch (cct) { 77 case DM_POLYTOPE_POINT: 78 case DM_POLYTOPE_SEGMENT: 79 case DM_POLYTOPE_TRIANGLE: 80 case DM_POLYTOPE_QUADRILATERAL: 81 case DM_POLYTOPE_TETRAHEDRON: 82 case DM_POLYTOPE_HEXAHEDRON: 83 ct = cct; 84 break; 85 default: break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) break; 88 } 89 if (ct != DM_POLYTOPE_UNKNOWN) { 90 DMLabel ctLabel; 91 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 94 // Reset label for fast lookup 95 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 96 } 97 if (cStart) *cStart = cS; 98 if (cEnd) *cEnd = cE; 99 PetscFunctionReturn(0); 100 } 101 102 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 103 { 104 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 105 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 106 107 PetscFunctionBegin; 108 *ft = PETSC_VTK_INVALID; 109 PetscCall(DMGetCoordinateDim(dm, &cdim)); 110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 111 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 112 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 113 if (field >= 0) { 114 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 115 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 116 } else { 117 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 118 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 119 } 120 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 121 if (globalvcdof[0]) { 122 *sStart = vStart; 123 *sEnd = vEnd; 124 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 125 else *ft = PETSC_VTK_POINT_FIELD; 126 } else if (globalvcdof[1]) { 127 *sStart = cStart; 128 *sEnd = cEnd; 129 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 130 else *ft = PETSC_VTK_CELL_FIELD; 131 } else { 132 if (field >= 0) { 133 const char *fieldname; 134 135 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 136 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 137 } else { 138 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 139 } 140 } 141 PetscFunctionReturn(0); 142 } 143 144 /*@ 145 DMPlexVecView1D - Plot many 1D solutions on the same line graph 146 147 Collective on dm 148 149 Input Parameters: 150 + dm - The DMPlex 151 . n - The number of vectors 152 . u - The array of local vectors 153 - viewer - The Draw viewer 154 155 Level: advanced 156 157 .seealso: `VecViewFromOptions()`, `VecView()` 158 @*/ 159 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 160 { 161 PetscDS ds; 162 PetscDraw draw = NULL; 163 PetscDrawLG lg; 164 Vec coordinates; 165 const PetscScalar *coords, **sol; 166 PetscReal *vals; 167 PetscInt *Nc; 168 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 169 char **names; 170 171 PetscFunctionBegin; 172 PetscCall(DMGetDS(dm, &ds)); 173 PetscCall(PetscDSGetNumFields(ds, &Nf)); 174 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 175 PetscCall(PetscDSGetComponents(ds, &Nc)); 176 177 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 178 if (!draw) PetscFunctionReturn(0); 179 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 180 181 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 182 for (i = 0, l = 0; i < n; ++i) { 183 const char *vname; 184 185 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 186 for (f = 0; f < Nf; ++f) { 187 PetscObject disc; 188 const char *fname; 189 char tmpname[PETSC_MAX_PATH_LEN]; 190 191 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 192 /* TODO Create names for components */ 193 for (c = 0; c < Nc[f]; ++c, ++l) { 194 PetscCall(PetscObjectGetName(disc, &fname)); 195 PetscCall(PetscStrcpy(tmpname, vname)); 196 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 197 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 198 PetscCall(PetscStrallocpy(tmpname, &names[l])); 199 } 200 } 201 } 202 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 203 /* Just add P_1 support for now */ 204 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 205 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 206 PetscCall(VecGetArrayRead(coordinates, &coords)); 207 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 208 for (v = vStart; v < vEnd; ++v) { 209 PetscScalar *x, *svals; 210 211 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 212 for (i = 0; i < n; ++i) { 213 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 214 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 215 } 216 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 217 } 218 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 219 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 220 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 221 PetscCall(PetscFree3(sol, names, vals)); 222 223 PetscCall(PetscDrawLGDraw(lg)); 224 PetscCall(PetscDrawLGDestroy(&lg)); 225 PetscFunctionReturn(0); 226 } 227 228 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 229 { 230 DM dm; 231 232 PetscFunctionBegin; 233 PetscCall(VecGetDM(u, &dm)); 234 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 235 PetscFunctionReturn(0); 236 } 237 238 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 239 { 240 DM dm; 241 PetscSection s; 242 PetscDraw draw, popup; 243 DM cdm; 244 PetscSection coordSection; 245 Vec coordinates; 246 const PetscScalar *coords, *array; 247 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 248 PetscReal vbound[2], time; 249 PetscBool flg; 250 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 251 const char *name; 252 char title[PETSC_MAX_PATH_LEN]; 253 254 PetscFunctionBegin; 255 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 256 PetscCall(VecGetDM(v, &dm)); 257 PetscCall(DMGetCoordinateDim(dm, &dim)); 258 PetscCall(DMGetLocalSection(dm, &s)); 259 PetscCall(PetscSectionGetNumFields(s, &Nf)); 260 PetscCall(DMGetCoarsenLevel(dm, &level)); 261 PetscCall(DMGetCoordinateDM(dm, &cdm)); 262 PetscCall(DMGetLocalSection(cdm, &coordSection)); 263 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 264 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 265 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 266 267 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 268 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 269 270 PetscCall(VecGetLocalSize(coordinates, &N)); 271 PetscCall(VecGetArrayRead(coordinates, &coords)); 272 for (c = 0; c < N; c += dim) { 273 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 274 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 275 } 276 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 277 PetscCall(PetscDrawClear(draw)); 278 279 /* Could implement something like DMDASelectFields() */ 280 for (f = 0; f < Nf; ++f) { 281 DM fdm = dm; 282 Vec fv = v; 283 IS fis; 284 char prefix[PETSC_MAX_PATH_LEN]; 285 const char *fname; 286 287 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 288 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 289 290 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 291 else {prefix[0] = '\0';} 292 if (Nf > 1) { 293 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 294 PetscCall(VecGetSubVector(v, fis, &fv)); 295 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 296 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 297 } 298 for (comp = 0; comp < Nc; ++comp, ++w) { 299 PetscInt nmax = 2; 300 301 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 302 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 303 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 304 PetscCall(PetscDrawSetTitle(draw, title)); 305 306 /* TODO Get max and min only for this component */ 307 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 308 if (!flg) { 309 PetscCall(VecMin(fv, NULL, &vbound[0])); 310 PetscCall(VecMax(fv, NULL, &vbound[1])); 311 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 312 } 313 PetscCall(PetscDrawGetPopup(draw, &popup)); 314 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 315 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 316 317 PetscCall(VecGetArrayRead(fv, &array)); 318 for (c = cStart; c < cEnd; ++c) { 319 PetscScalar *coords = NULL, *a = NULL; 320 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 321 322 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 323 if (a) { 324 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 325 color[1] = color[2] = color[3] = color[0]; 326 } else { 327 PetscScalar *vals = NULL; 328 PetscInt numVals, va; 329 330 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 331 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 332 switch (numVals/Nc) { 333 case 3: /* P1 Triangle */ 334 case 4: /* P1 Quadrangle */ 335 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 336 break; 337 case 6: /* P2 Triangle */ 338 case 8: /* P2 Quadrangle */ 339 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 340 break; 341 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 342 } 343 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 344 } 345 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 346 switch (numCoords) { 347 case 6: 348 case 12: /* Localized triangle */ 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 break; 351 case 8: 352 case 16: /* Localized quadrilateral */ 353 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])); 354 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])); 355 break; 356 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 357 } 358 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 359 } 360 PetscCall(VecRestoreArrayRead(fv, &array)); 361 PetscCall(PetscDrawFlush(draw)); 362 PetscCall(PetscDrawPause(draw)); 363 PetscCall(PetscDrawSave(draw)); 364 } 365 if (Nf > 1) { 366 PetscCall(VecRestoreSubVector(v, fis, &fv)); 367 PetscCall(ISDestroy(&fis)); 368 PetscCall(DMDestroy(&fdm)); 369 } 370 } 371 PetscFunctionReturn(0); 372 } 373 374 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 375 { 376 DM dm; 377 PetscDraw draw; 378 PetscInt dim; 379 PetscBool isnull; 380 381 PetscFunctionBegin; 382 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 383 PetscCall(PetscDrawIsNull(draw, &isnull)); 384 if (isnull) PetscFunctionReturn(0); 385 386 PetscCall(VecGetDM(v, &dm)); 387 PetscCall(DMGetCoordinateDim(dm, &dim)); 388 switch (dim) { 389 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 390 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 391 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 397 { 398 DM dm; 399 Vec locv; 400 const char *name; 401 PetscSection section; 402 PetscInt pStart, pEnd; 403 PetscInt numFields; 404 PetscViewerVTKFieldType ft; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(v, &dm)); 408 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 409 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 410 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 411 PetscCall(VecCopy(v, locv)); 412 PetscCall(DMGetLocalSection(dm, §ion)); 413 PetscCall(PetscSectionGetNumFields(section, &numFields)); 414 if (!numFields) { 415 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 416 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 417 } else { 418 PetscInt f; 419 420 for (f = 0; f < numFields; f++) { 421 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 422 if (ft == PETSC_VTK_INVALID) continue; 423 PetscCall(PetscObjectReference((PetscObject)locv)); 424 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 425 } 426 PetscCall(VecDestroy(&locv)); 427 } 428 PetscFunctionReturn(0); 429 } 430 431 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 432 { 433 DM dm; 434 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 435 436 PetscFunctionBegin; 437 PetscCall(VecGetDM(v, &dm)); 438 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 439 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 440 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 441 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 442 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 443 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 444 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 445 PetscInt i,numFields; 446 PetscObject fe; 447 PetscBool fem = PETSC_FALSE; 448 Vec locv = v; 449 const char *name; 450 PetscInt step; 451 PetscReal time; 452 453 PetscCall(DMGetNumFields(dm, &numFields)); 454 for (i=0; i<numFields; i++) { 455 PetscCall(DMGetField(dm, i, NULL, &fe)); 456 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 457 } 458 if (fem) { 459 PetscObject isZero; 460 461 PetscCall(DMGetLocalVector(dm, &locv)); 462 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 463 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 464 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 465 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 466 PetscCall(VecCopy(v, locv)); 467 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 468 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 469 } 470 if (isvtk) { 471 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 472 } else if (ishdf5) { 473 #if defined(PETSC_HAVE_HDF5) 474 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 475 #else 476 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 477 #endif 478 } else if (isdraw) { 479 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 480 } else if (isglvis) { 481 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 482 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 483 PetscCall(VecView_GLVis(locv, viewer)); 484 } else if (iscgns) { 485 #if defined(PETSC_HAVE_CGNS) 486 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 487 #else 488 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 489 #endif 490 } 491 if (fem) { 492 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 493 PetscCall(DMRestoreLocalVector(dm, &locv)); 494 } 495 } else { 496 PetscBool isseq; 497 498 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 499 if (isseq) PetscCall(VecView_Seq(v, viewer)); 500 else PetscCall(VecView_MPI(v, viewer)); 501 } 502 PetscFunctionReturn(0); 503 } 504 505 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 506 { 507 DM dm; 508 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 509 510 PetscFunctionBegin; 511 PetscCall(VecGetDM(v, &dm)); 512 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 513 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 514 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 515 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 516 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 517 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 518 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 519 if (isvtk || isdraw || isglvis || iscgns) { 520 Vec locv; 521 PetscObject isZero; 522 const char *name; 523 524 PetscCall(DMGetLocalVector(dm, &locv)); 525 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 526 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 527 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 528 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 529 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 530 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 531 PetscCall(VecView_Plex_Local(locv, viewer)); 532 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 533 PetscCall(DMRestoreLocalVector(dm, &locv)); 534 } else if (ishdf5) { 535 #if defined(PETSC_HAVE_HDF5) 536 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 537 #else 538 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 539 #endif 540 } else if (isexodusii) { 541 #if defined(PETSC_HAVE_EXODUSII) 542 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 543 #else 544 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 545 #endif 546 } else { 547 PetscBool isseq; 548 549 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 550 if (isseq) PetscCall(VecView_Seq(v, viewer)); 551 else PetscCall(VecView_MPI(v, viewer)); 552 } 553 PetscFunctionReturn(0); 554 } 555 556 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 557 { 558 DM dm; 559 MPI_Comm comm; 560 PetscViewerFormat format; 561 Vec v; 562 PetscBool isvtk, ishdf5; 563 564 PetscFunctionBegin; 565 PetscCall(VecGetDM(originalv, &dm)); 566 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 567 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 568 PetscCall(PetscViewerGetFormat(viewer, &format)); 569 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 570 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 571 if (format == PETSC_VIEWER_NATIVE) { 572 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 573 /* this need a better fix */ 574 if (dm->useNatural) { 575 if (dm->sfNatural) { 576 const char *vecname; 577 PetscInt n, nroots; 578 579 PetscCall(VecGetLocalSize(originalv, &n)); 580 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 581 if (n == nroots) { 582 PetscCall(DMGetGlobalVector(dm, &v)); 583 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 584 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 585 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 586 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 587 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 588 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 589 } else v = originalv; 590 } else v = originalv; 591 592 if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 595 #else 596 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isvtk) { 599 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 600 } else { 601 PetscBool isseq; 602 603 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 604 if (isseq) PetscCall(VecView_Seq(v, viewer)); 605 else PetscCall(VecView_MPI(v, viewer)); 606 } 607 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 608 PetscFunctionReturn(0); 609 } 610 611 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 612 { 613 DM dm; 614 PetscBool ishdf5; 615 616 PetscFunctionBegin; 617 PetscCall(VecGetDM(v, &dm)); 618 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 619 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 620 if (ishdf5) { 621 DM dmBC; 622 Vec gv; 623 const char *name; 624 625 PetscCall(DMGetOutputDM(dm, &dmBC)); 626 PetscCall(DMGetGlobalVector(dmBC, &gv)); 627 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 628 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 629 PetscCall(VecLoad_Default(gv, viewer)); 630 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 631 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 632 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 633 } else PetscCall(VecLoad_Default(v, viewer)); 634 PetscFunctionReturn(0); 635 } 636 637 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 638 { 639 DM dm; 640 PetscBool ishdf5,isexodusii; 641 642 PetscFunctionBegin; 643 PetscCall(VecGetDM(v, &dm)); 644 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 645 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 646 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 647 if (ishdf5) { 648 #if defined(PETSC_HAVE_HDF5) 649 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 650 #else 651 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 652 #endif 653 } else if (isexodusii) { 654 #if defined(PETSC_HAVE_EXODUSII) 655 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 658 #endif 659 } else PetscCall(VecLoad_Default(v, viewer)); 660 PetscFunctionReturn(0); 661 } 662 663 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 664 { 665 DM dm; 666 PetscViewerFormat format; 667 PetscBool ishdf5; 668 669 PetscFunctionBegin; 670 PetscCall(VecGetDM(originalv, &dm)); 671 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 672 PetscCall(PetscViewerGetFormat(viewer, &format)); 673 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 674 if (format == PETSC_VIEWER_NATIVE) { 675 if (dm->useNatural) { 676 if (dm->sfNatural) { 677 if (ishdf5) { 678 #if defined(PETSC_HAVE_HDF5) 679 Vec v; 680 const char *vecname; 681 682 PetscCall(DMGetGlobalVector(dm, &v)); 683 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 684 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 685 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 686 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 687 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 688 PetscCall(DMRestoreGlobalVector(dm, &v)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 691 #endif 692 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 693 } 694 } else PetscCall(VecLoad_Default(originalv, viewer)); 695 } 696 PetscFunctionReturn(0); 697 } 698 699 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 700 { 701 PetscSection coordSection; 702 Vec coordinates; 703 DMLabel depthLabel, celltypeLabel; 704 const char *name[4]; 705 const PetscScalar *a; 706 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 707 708 PetscFunctionBegin; 709 PetscCall(DMGetDimension(dm, &dim)); 710 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 711 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 712 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 713 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 715 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 716 PetscCall(VecGetArrayRead(coordinates, &a)); 717 name[0] = "vertex"; 718 name[1] = "edge"; 719 name[dim-1] = "face"; 720 name[dim] = "cell"; 721 for (c = cStart; c < cEnd; ++c) { 722 PetscInt *closure = NULL; 723 PetscInt closureSize, cl, ct; 724 725 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 726 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 727 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 728 PetscCall(PetscViewerASCIIPushTab(viewer)); 729 for (cl = 0; cl < closureSize*2; cl += 2) { 730 PetscInt point = closure[cl], depth, dof, off, d, p; 731 732 if ((point < pStart) || (point >= pEnd)) continue; 733 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 734 if (!dof) continue; 735 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 736 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 737 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 738 for (p = 0; p < dof/dim; ++p) { 739 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 740 for (d = 0; d < dim; ++d) { 741 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 743 } 744 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 745 } 746 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 747 } 748 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 749 PetscCall(PetscViewerASCIIPopTab(viewer)); 750 } 751 PetscCall(VecRestoreArrayRead(coordinates, &a)); 752 PetscFunctionReturn(0); 753 } 754 755 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 756 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 757 758 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 759 { 760 PetscInt i; 761 762 PetscFunctionBegin; 763 if (dim > 3) { 764 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 765 } else { 766 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 767 768 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 769 switch (cs) { 770 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 771 case CS_POLAR: 772 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 773 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 774 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 775 break; 776 case CS_CYLINDRICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 779 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 780 trcoords[2] = coords[2]; 781 break; 782 case CS_SPHERICAL: 783 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 784 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 785 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 786 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 787 break; 788 } 789 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 790 } 791 PetscFunctionReturn(0); 792 } 793 794 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 795 { 796 DM_Plex *mesh = (DM_Plex*) dm->data; 797 DM cdm, cdmCell; 798 PetscSection coordSection, coordSectionCell; 799 Vec coordinates, coordinatesCell; 800 PetscViewerFormat format; 801 802 PetscFunctionBegin; 803 PetscCall(DMGetCoordinateDM(dm, &cdm)); 804 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 805 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 806 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 807 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 808 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 809 PetscCall(PetscViewerGetFormat(viewer, &format)); 810 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 811 const char *name; 812 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 813 PetscInt pStart, pEnd, p, numLabels, l; 814 PetscMPIInt rank, size; 815 816 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 817 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 818 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 819 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 820 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 821 PetscCall(DMGetDimension(dm, &dim)); 822 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 823 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 824 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 825 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 826 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 827 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 828 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 829 for (p = pStart; p < pEnd; ++p) { 830 PetscInt dof, off, s; 831 832 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 833 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 834 for (s = off; s < off+dof; ++s) { 835 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 836 } 837 } 838 PetscCall(PetscViewerFlush(viewer)); 839 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 840 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 841 for (p = pStart; p < pEnd; ++p) { 842 PetscInt dof, off, c; 843 844 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 845 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 846 for (c = off; c < off+dof; ++c) { 847 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 848 } 849 } 850 PetscCall(PetscViewerFlush(viewer)); 851 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 852 if (coordSection && coordinates) { 853 CoordSystem cs = CS_CARTESIAN; 854 const PetscScalar *array, *arrayCell = NULL; 855 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 856 PetscMPIInt rank; 857 const char *name; 858 859 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 860 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 861 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 862 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 863 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 864 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 865 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 866 pStart = PetscMin(pvStart, pcStart); 867 pEnd = PetscMax(pvEnd, pcEnd); 868 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 869 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 870 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 871 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 872 873 PetscCall(VecGetArrayRead(coordinates, &array)); 874 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 875 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 877 for (p = pStart; p < pEnd; ++p) { 878 PetscInt dof, off; 879 880 if (p >= pvStart && p < pvEnd) { 881 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 882 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 883 if (dof) { 884 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 885 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 886 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 887 } 888 } 889 if (cdmCell && p >= pcStart && p < pcEnd) { 890 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 891 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 892 if (dof) { 893 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 894 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 896 } 897 } 898 } 899 PetscCall(PetscViewerFlush(viewer)); 900 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 901 PetscCall(VecRestoreArrayRead(coordinates, &array)); 902 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 903 } 904 PetscCall(DMGetNumLabels(dm, &numLabels)); 905 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 906 for (l = 0; l < numLabels; ++l) { 907 DMLabel label; 908 PetscBool isdepth; 909 const char *name; 910 911 PetscCall(DMGetLabelName(dm, l, &name)); 912 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 913 if (isdepth) continue; 914 PetscCall(DMGetLabel(dm, name, &label)); 915 PetscCall(DMLabelView(label, viewer)); 916 } 917 if (size > 1) { 918 PetscSF sf; 919 920 PetscCall(DMGetPointSF(dm, &sf)); 921 PetscCall(PetscSFView(sf, viewer)); 922 } 923 PetscCall(PetscViewerFlush(viewer)); 924 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 925 const char *name, *color; 926 const char *defcolors[3] = {"gray", "orange", "green"}; 927 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 928 char lname[PETSC_MAX_PATH_LEN]; 929 PetscReal scale = 2.0; 930 PetscReal tikzscale = 1.0; 931 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 932 double tcoords[3]; 933 PetscScalar *coords; 934 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 935 PetscMPIInt rank, size; 936 char **names, **colors, **lcolors; 937 PetscBool flg, lflg; 938 PetscBT wp = NULL; 939 PetscInt pEnd, pStart; 940 941 PetscCall(DMGetDimension(dm, &dim)); 942 PetscCall(DMPlexGetDepth(dm, &depth)); 943 PetscCall(DMGetNumLabels(dm, &numLabels)); 944 numLabels = PetscMax(numLabels, 10); 945 numColors = 10; 946 numLColors = 10; 947 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 948 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 949 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 950 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 951 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 952 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 953 n = 4; 954 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 955 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 956 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 957 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 958 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 959 if (!useLabels) numLabels = 0; 960 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 961 if (!useColors) { 962 numColors = 3; 963 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 964 } 965 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 966 if (!useColors) { 967 numLColors = 4; 968 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 969 } 970 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 971 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 972 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 973 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 974 if (depth < dim) plotEdges = PETSC_FALSE; 975 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 976 977 /* filter points with labelvalue != labeldefaultvalue */ 978 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 979 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 980 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 981 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 982 if (lflg) { 983 DMLabel lbl; 984 985 PetscCall(DMGetLabel(dm, lname, &lbl)); 986 if (lbl) { 987 PetscInt val, defval; 988 989 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 990 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 991 for (c = pStart; c < pEnd; c++) { 992 PetscInt *closure = NULL; 993 PetscInt closureSize; 994 995 PetscCall(DMLabelGetValue(lbl, c, &val)); 996 if (val == defval) continue; 997 998 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 999 for (p = 0; p < closureSize*2; p += 2) { 1000 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1001 } 1002 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1003 } 1004 } 1005 } 1006 1007 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1008 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1009 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1011 \\documentclass[tikz]{standalone}\n\n\ 1012 \\usepackage{pgflibraryshapes}\n\ 1013 \\usetikzlibrary{backgrounds}\n\ 1014 \\usetikzlibrary{arrows}\n\ 1015 \\begin{document}\n")); 1016 if (size > 1) { 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1018 for (p = 0; p < size; ++p) { 1019 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1021 } 1022 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1023 } 1024 if (drawHasse) { 1025 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1026 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1032 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1033 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1034 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1035 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1037 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1039 } 1040 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1041 1042 /* Plot vertices */ 1043 PetscCall(VecGetArray(coordinates, &coords)); 1044 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1045 for (v = vStart; v < vEnd; ++v) { 1046 PetscInt off, dof, d; 1047 PetscBool isLabeled = PETSC_FALSE; 1048 1049 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1050 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1051 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1052 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1053 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1054 for (d = 0; d < dof; ++d) { 1055 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1056 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1057 } 1058 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1059 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1060 for (d = 0; d < dof; ++d) { 1061 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1062 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1063 } 1064 if (drawHasse) color = colors[0%numColors]; 1065 else color = colors[rank%numColors]; 1066 for (l = 0; l < numLabels; ++l) { 1067 PetscInt val; 1068 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1069 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1070 } 1071 if (drawNumbers[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1073 } else if (drawColors[0]) { 1074 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1075 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1076 } 1077 PetscCall(VecRestoreArray(coordinates, &coords)); 1078 PetscCall(PetscViewerFlush(viewer)); 1079 /* Plot edges */ 1080 if (plotEdges) { 1081 PetscCall(VecGetArray(coordinates, &coords)); 1082 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1083 for (e = eStart; e < eEnd; ++e) { 1084 const PetscInt *cone; 1085 PetscInt coneSize, offA, offB, dof, d; 1086 1087 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1088 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1089 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1090 PetscCall(DMPlexGetCone(dm, e, &cone)); 1091 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1092 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1093 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1094 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1095 for (d = 0; d < dof; ++d) { 1096 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1097 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1098 } 1099 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1100 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1101 for (d = 0; d < dof; ++d) { 1102 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1104 } 1105 if (drawHasse) color = colors[1%numColors]; 1106 else color = colors[rank%numColors]; 1107 for (l = 0; l < numLabels; ++l) { 1108 PetscInt val; 1109 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1110 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1111 } 1112 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1113 } 1114 PetscCall(VecRestoreArray(coordinates, &coords)); 1115 PetscCall(PetscViewerFlush(viewer)); 1116 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1117 } 1118 /* Plot cells */ 1119 if (dim == 3 || !drawNumbers[1]) { 1120 for (e = eStart; e < eEnd; ++e) { 1121 const PetscInt *cone; 1122 1123 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1124 color = colors[rank%numColors]; 1125 for (l = 0; l < numLabels; ++l) { 1126 PetscInt val; 1127 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1128 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1129 } 1130 PetscCall(DMPlexGetCone(dm, e, &cone)); 1131 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1132 } 1133 } else { 1134 DMPolytopeType ct; 1135 1136 /* Drawing a 2D polygon */ 1137 for (c = cStart; c < cEnd; ++c) { 1138 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1139 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1140 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1141 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1142 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1143 const PetscInt *cone; 1144 PetscInt coneSize, e; 1145 1146 PetscCall(DMPlexGetCone(dm, c, &cone)); 1147 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1148 for (e = 0; e < coneSize; ++e) { 1149 const PetscInt *econe; 1150 1151 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1152 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1153 } 1154 } else { 1155 PetscInt *closure = NULL; 1156 PetscInt closureSize, Nv = 0, v; 1157 1158 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1159 for (p = 0; p < closureSize*2; p += 2) { 1160 const PetscInt point = closure[p]; 1161 1162 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1163 } 1164 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1165 for (v = 0; v <= Nv; ++v) { 1166 const PetscInt vertex = closure[v%Nv]; 1167 1168 if (v > 0) { 1169 if (plotEdges) { 1170 const PetscInt *edge; 1171 PetscInt endpoints[2], ne; 1172 1173 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1174 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1175 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1176 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1177 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1178 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1179 } 1180 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1181 } 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1183 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1184 } 1185 } 1186 } 1187 for (c = cStart; c < cEnd; ++c) { 1188 double ccoords[3] = {0.0, 0.0, 0.0}; 1189 PetscBool isLabeled = PETSC_FALSE; 1190 PetscScalar *cellCoords = NULL; 1191 const PetscScalar *array; 1192 PetscInt numCoords, cdim, d; 1193 PetscBool isDG; 1194 1195 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1196 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1197 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1198 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1199 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1200 for (p = 0; p < numCoords/cdim; ++p) { 1201 for (d = 0; d < cdim; ++d) { 1202 tcoords[d] = (double) (scale*PetscRealPart(cellCoords[p*cdim+d])); 1203 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1204 } 1205 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1206 if (cdim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1207 for (d = 0; d < dim; ++d) {ccoords[d] += tcoords[d];} 1208 } 1209 for (d = 0; d < cdim; ++d) {ccoords[d] /= (numCoords/cdim);} 1210 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1211 for (d = 0; d < cdim; ++d) { 1212 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1213 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1214 } 1215 if (drawHasse) color = colors[depth%numColors]; 1216 else color = colors[rank%numColors]; 1217 for (l = 0; l < numLabels; ++l) { 1218 PetscInt val; 1219 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1220 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1221 } 1222 if (drawNumbers[dim]) { 1223 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1224 } else if (drawColors[dim]) { 1225 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1226 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1227 } 1228 if (drawHasse) { 1229 color = colors[depth%numColors]; 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1235 1236 color = colors[1%numColors]; 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1242 1243 color = colors[0%numColors]; 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1249 1250 for (p = pStart; p < pEnd; ++p) { 1251 const PetscInt *cone; 1252 PetscInt coneSize, cp; 1253 1254 PetscCall(DMPlexGetCone(dm, p, &cone)); 1255 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1256 for (cp = 0; cp < coneSize; ++cp) { 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1258 } 1259 } 1260 } 1261 PetscCall(PetscViewerFlush(viewer)); 1262 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1265 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1266 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1267 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1268 PetscCall(PetscFree3(names, colors, lcolors)); 1269 PetscCall(PetscBTDestroy(&wp)); 1270 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1271 Vec cown,acown; 1272 VecScatter sct; 1273 ISLocalToGlobalMapping g2l; 1274 IS gid,acis; 1275 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1276 MPI_Group ggroup,ngroup; 1277 PetscScalar *array,nid; 1278 const PetscInt *idxs; 1279 PetscInt *idxs2,*start,*adjacency,*work; 1280 PetscInt64 lm[3],gm[3]; 1281 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1282 PetscMPIInt d1,d2,rank; 1283 1284 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1285 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1286 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1287 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1288 #endif 1289 if (ncomm != MPI_COMM_NULL) { 1290 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1291 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1292 d1 = 0; 1293 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1294 nid = d2; 1295 PetscCallMPI(MPI_Group_free(&ggroup)); 1296 PetscCallMPI(MPI_Group_free(&ngroup)); 1297 PetscCallMPI(MPI_Comm_free(&ncomm)); 1298 } else nid = 0.0; 1299 1300 /* Get connectivity */ 1301 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1302 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1303 1304 /* filter overlapped local cells */ 1305 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1306 PetscCall(ISGetIndices(gid,&idxs)); 1307 PetscCall(ISGetLocalSize(gid,&cum)); 1308 PetscCall(PetscMalloc1(cum,&idxs2)); 1309 for (c = cStart, cum = 0; c < cEnd; c++) { 1310 if (idxs[c-cStart] < 0) continue; 1311 idxs2[cum++] = idxs[c-cStart]; 1312 } 1313 PetscCall(ISRestoreIndices(gid,&idxs)); 1314 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1315 PetscCall(ISDestroy(&gid)); 1316 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1317 1318 /* support for node-aware cell locality */ 1319 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1320 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1321 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1322 PetscCall(VecGetArray(cown,&array)); 1323 for (c = 0; c < numVertices; c++) array[c] = nid; 1324 PetscCall(VecRestoreArray(cown,&array)); 1325 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1326 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1327 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1328 PetscCall(ISDestroy(&acis)); 1329 PetscCall(VecScatterDestroy(&sct)); 1330 PetscCall(VecDestroy(&cown)); 1331 1332 /* compute edgeCut */ 1333 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1334 PetscCall(PetscMalloc1(cum,&work)); 1335 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1336 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1337 PetscCall(ISDestroy(&gid)); 1338 PetscCall(VecGetArray(acown,&array)); 1339 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1340 PetscInt totl; 1341 1342 totl = start[c+1]-start[c]; 1343 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1344 for (i = 0; i < totl; i++) { 1345 if (work[i] < 0) { 1346 ect += 1; 1347 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1348 } 1349 } 1350 } 1351 PetscCall(PetscFree(work)); 1352 PetscCall(VecRestoreArray(acown,&array)); 1353 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1354 lm[1] = -numVertices; 1355 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1356 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1357 lm[0] = ect; /* edgeCut */ 1358 lm[1] = ectn; /* node-aware edgeCut */ 1359 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1360 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1361 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1362 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1363 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1364 #else 1365 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1366 #endif 1367 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1368 PetscCall(PetscFree(start)); 1369 PetscCall(PetscFree(adjacency)); 1370 PetscCall(VecDestroy(&acown)); 1371 } else { 1372 const char *name; 1373 PetscInt *sizes, *hybsizes, *ghostsizes; 1374 PetscInt locDepth, depth, cellHeight, dim, d; 1375 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1376 PetscInt numLabels, l, maxSize = 17; 1377 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1378 MPI_Comm comm; 1379 PetscMPIInt size, rank; 1380 1381 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1382 PetscCallMPI(MPI_Comm_size(comm, &size)); 1383 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1384 PetscCall(DMGetDimension(dm, &dim)); 1385 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1386 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1387 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1388 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1389 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1390 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1391 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1392 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1393 gcNum = gcEnd - gcStart; 1394 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1395 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1396 for (d = 0; d <= depth; d++) { 1397 PetscInt Nc[2] = {0, 0}, ict; 1398 1399 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1400 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1401 ict = ct0; 1402 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1403 ct0 = (DMPolytopeType) ict; 1404 for (p = pStart; p < pEnd; ++p) { 1405 DMPolytopeType ct; 1406 1407 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1408 if (ct == ct0) ++Nc[0]; 1409 else ++Nc[1]; 1410 } 1411 if (size < maxSize) { 1412 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1413 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1414 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1416 for (p = 0; p < size; ++p) { 1417 if (rank == 0) { 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1419 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1420 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1421 } 1422 } 1423 } else { 1424 PetscInt locMinMax[2]; 1425 1426 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1427 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1428 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1429 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1430 if (d == depth) { 1431 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1432 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1433 } 1434 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1436 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1437 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1438 } 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1440 } 1441 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1442 { 1443 const PetscReal *maxCell; 1444 const PetscReal *L; 1445 PetscBool localized; 1446 1447 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1448 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1449 if (L || localized) { 1450 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1451 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1452 if (L) { 1453 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1454 for (d = 0; d < dim; ++d) { 1455 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1456 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1457 } 1458 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1459 } 1460 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1461 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1462 } 1463 } 1464 PetscCall(DMGetNumLabels(dm, &numLabels)); 1465 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1466 for (l = 0; l < numLabels; ++l) { 1467 DMLabel label; 1468 const char *name; 1469 IS valueIS; 1470 const PetscInt *values; 1471 PetscInt numValues, v; 1472 1473 PetscCall(DMGetLabelName(dm, l, &name)); 1474 PetscCall(DMGetLabel(dm, name, &label)); 1475 PetscCall(DMLabelGetNumValues(label, &numValues)); 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1477 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1478 PetscCall(ISGetIndices(valueIS, &values)); 1479 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1480 for (v = 0; v < numValues; ++v) { 1481 PetscInt size; 1482 1483 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1484 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1486 } 1487 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1488 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1489 PetscCall(ISRestoreIndices(valueIS, &values)); 1490 PetscCall(ISDestroy(&valueIS)); 1491 } 1492 { 1493 char **labelNames; 1494 PetscInt Nl = numLabels; 1495 PetscBool flg; 1496 1497 PetscCall(PetscMalloc1(Nl, &labelNames)); 1498 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1499 for (l = 0; l < Nl; ++l) { 1500 DMLabel label; 1501 1502 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1503 if (flg) { 1504 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1505 PetscCall(DMLabelView(label, viewer)); 1506 } 1507 PetscCall(PetscFree(labelNames[l])); 1508 } 1509 PetscCall(PetscFree(labelNames)); 1510 } 1511 /* If no fields are specified, people do not want to see adjacency */ 1512 if (dm->Nf) { 1513 PetscInt f; 1514 1515 for (f = 0; f < dm->Nf; ++f) { 1516 const char *name; 1517 1518 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1519 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1520 PetscCall(PetscViewerASCIIPushTab(viewer)); 1521 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1522 if (dm->fields[f].adjacency[0]) { 1523 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1524 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1525 } else { 1526 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1527 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1528 } 1529 PetscCall(PetscViewerASCIIPopTab(viewer)); 1530 } 1531 } 1532 PetscCall(DMGetCoarseDM(dm, &cdm)); 1533 if (cdm) { 1534 PetscCall(PetscViewerASCIIPushTab(viewer)); 1535 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1536 PetscCall(PetscViewerASCIIPopTab(viewer)); 1537 } 1538 } 1539 PetscFunctionReturn(0); 1540 } 1541 1542 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1543 { 1544 DMPolytopeType ct; 1545 PetscMPIInt rank; 1546 PetscInt cdim; 1547 1548 PetscFunctionBegin; 1549 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1550 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1551 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1552 switch (ct) { 1553 case DM_POLYTOPE_SEGMENT: 1554 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1555 switch (cdim) { 1556 case 1: 1557 { 1558 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1559 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1560 1561 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1562 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1563 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1564 } 1565 break; 1566 case 2: 1567 { 1568 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1569 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1570 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1571 1572 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1573 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)); 1574 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)); 1575 } 1576 break; 1577 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1578 } 1579 break; 1580 case DM_POLYTOPE_TRIANGLE: 1581 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1582 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1583 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1584 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1587 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1588 break; 1589 case DM_POLYTOPE_QUADRILATERAL: 1590 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1591 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1592 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1593 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1594 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1595 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1596 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1597 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1598 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1599 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1602 break; 1603 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1604 } 1605 PetscFunctionReturn(0); 1606 } 1607 1608 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1609 { 1610 DMPolytopeType ct; 1611 PetscReal centroid[2] = {0., 0.}; 1612 PetscMPIInt rank; 1613 PetscInt fillColor, v, e, d; 1614 1615 PetscFunctionBegin; 1616 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1617 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1618 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1619 switch (ct) { 1620 case DM_POLYTOPE_TRIANGLE: 1621 { 1622 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1623 1624 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1625 for (e = 0; e < 3; ++e) { 1626 refCoords[0] = refVertices[e*2+0]; 1627 refCoords[1] = refVertices[e*2+1]; 1628 for (d = 1; d <= edgeDiv; ++d) { 1629 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1630 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1631 } 1632 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1633 for (d = 0; d < edgeDiv; ++d) { 1634 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)); 1635 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1636 } 1637 } 1638 } 1639 break; 1640 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1641 } 1642 PetscFunctionReturn(0); 1643 } 1644 1645 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1646 { 1647 PetscDraw draw; 1648 DM cdm; 1649 PetscSection coordSection; 1650 Vec coordinates; 1651 const PetscScalar *coords; 1652 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1653 PetscReal *refCoords, *edgeCoords; 1654 PetscBool isnull, drawAffine = PETSC_TRUE; 1655 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1656 1657 PetscFunctionBegin; 1658 PetscCall(DMGetCoordinateDim(dm, &dim)); 1659 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1660 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1661 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1662 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1663 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1664 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1665 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1666 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1667 1668 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1669 PetscCall(PetscDrawIsNull(draw, &isnull)); 1670 if (isnull) PetscFunctionReturn(0); 1671 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1672 1673 PetscCall(VecGetLocalSize(coordinates, &N)); 1674 PetscCall(VecGetArrayRead(coordinates, &coords)); 1675 for (c = 0; c < N; c += dim) { 1676 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1677 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1678 } 1679 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1680 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1681 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1682 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1683 PetscCall(PetscDrawClear(draw)); 1684 1685 for (c = cStart; c < cEnd; ++c) { 1686 PetscScalar *coords = NULL; 1687 PetscInt numCoords; 1688 1689 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1690 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1691 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1692 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1693 } 1694 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1695 PetscCall(PetscDrawFlush(draw)); 1696 PetscCall(PetscDrawPause(draw)); 1697 PetscCall(PetscDrawSave(draw)); 1698 PetscFunctionReturn(0); 1699 } 1700 1701 #if defined(PETSC_HAVE_EXODUSII) 1702 #include <exodusII.h> 1703 #include <petscviewerexodusii.h> 1704 #endif 1705 1706 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1707 { 1708 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1709 char name[PETSC_MAX_PATH_LEN]; 1710 1711 PetscFunctionBegin; 1712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1713 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1714 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1715 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1716 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1717 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 1721 if (iascii) { 1722 PetscViewerFormat format; 1723 PetscCall(PetscViewerGetFormat(viewer, &format)); 1724 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1725 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1726 } else if (ishdf5) { 1727 #if defined(PETSC_HAVE_HDF5) 1728 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1729 #else 1730 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1731 #endif 1732 } else if (isvtk) { 1733 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1734 } else if (isdraw) { 1735 PetscCall(DMPlexView_Draw(dm, viewer)); 1736 } else if (isglvis) { 1737 PetscCall(DMPlexView_GLVis(dm, viewer)); 1738 #if defined(PETSC_HAVE_EXODUSII) 1739 } else if (isexodus) { 1740 /* 1741 exodusII requires that all sets be part of exactly one cell set. 1742 If the dm does not have a "Cell Sets" label defined, we create one 1743 with ID 1, containig all cells. 1744 Note that if the Cell Sets label is defined but does not cover all cells, 1745 we may still have a problem. This should probably be checked here or in the viewer; 1746 */ 1747 PetscInt numCS; 1748 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1749 if (!numCS) { 1750 PetscInt cStart, cEnd, c; 1751 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1752 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1753 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1754 } 1755 PetscCall(DMView_PlexExodusII(dm, viewer)); 1756 #endif 1757 #if defined(PETSC_HAVE_CGNS) 1758 } else if (iscgns) { 1759 PetscCall(DMView_PlexCGNS(dm, viewer)); 1760 #endif 1761 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1762 /* Optionally view the partition */ 1763 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1764 if (flg) { 1765 Vec ranks; 1766 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1767 PetscCall(VecView(ranks, viewer)); 1768 PetscCall(VecDestroy(&ranks)); 1769 } 1770 /* Optionally view a label */ 1771 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1772 if (flg) { 1773 DMLabel label; 1774 Vec val; 1775 1776 PetscCall(DMGetLabel(dm, name, &label)); 1777 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1778 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1779 PetscCall(VecView(val, viewer)); 1780 PetscCall(VecDestroy(&val)); 1781 } 1782 PetscFunctionReturn(0); 1783 } 1784 1785 /*@ 1786 DMPlexTopologyView - Saves a DMPlex topology into a file 1787 1788 Collective on DM 1789 1790 Input Parameters: 1791 + dm - The DM whose topology is to be saved 1792 - viewer - The PetscViewer for saving 1793 1794 Level: advanced 1795 1796 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1797 @*/ 1798 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1799 { 1800 PetscBool ishdf5; 1801 1802 PetscFunctionBegin; 1803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1804 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1805 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1806 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1807 if (ishdf5) { 1808 #if defined(PETSC_HAVE_HDF5) 1809 PetscViewerFormat format; 1810 PetscCall(PetscViewerGetFormat(viewer, &format)); 1811 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1812 IS globalPointNumbering; 1813 1814 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1815 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1816 PetscCall(ISDestroy(&globalPointNumbering)); 1817 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1818 #else 1819 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1820 #endif 1821 } 1822 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1823 PetscFunctionReturn(0); 1824 } 1825 1826 /*@ 1827 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1828 1829 Collective on DM 1830 1831 Input Parameters: 1832 + dm - The DM whose coordinates are to be saved 1833 - viewer - The PetscViewer for saving 1834 1835 Level: advanced 1836 1837 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1838 @*/ 1839 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1840 { 1841 PetscBool ishdf5; 1842 1843 PetscFunctionBegin; 1844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1845 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1846 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1847 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1848 if (ishdf5) { 1849 #if defined(PETSC_HAVE_HDF5) 1850 PetscViewerFormat format; 1851 PetscCall(PetscViewerGetFormat(viewer, &format)); 1852 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1853 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1854 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1855 #else 1856 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1857 #endif 1858 } 1859 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*@ 1864 DMPlexLabelsView - Saves DMPlex labels into a file 1865 1866 Collective on DM 1867 1868 Input Parameters: 1869 + dm - The DM whose labels are to be saved 1870 - viewer - The PetscViewer for saving 1871 1872 Level: advanced 1873 1874 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1875 @*/ 1876 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1877 { 1878 PetscBool ishdf5; 1879 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1882 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1883 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1884 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1885 if (ishdf5) { 1886 #if defined(PETSC_HAVE_HDF5) 1887 IS globalPointNumbering; 1888 PetscViewerFormat format; 1889 1890 PetscCall(PetscViewerGetFormat(viewer, &format)); 1891 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1892 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1893 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1894 PetscCall(ISDestroy(&globalPointNumbering)); 1895 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1896 #else 1897 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1898 #endif 1899 } 1900 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1901 PetscFunctionReturn(0); 1902 } 1903 1904 /*@ 1905 DMPlexSectionView - Saves a section associated with a DMPlex 1906 1907 Collective on DM 1908 1909 Input Parameters: 1910 + dm - The DM that contains the topology on which the section to be saved is defined 1911 . viewer - The PetscViewer for saving 1912 - sectiondm - The DM that contains the section to be saved 1913 1914 Level: advanced 1915 1916 Notes: 1917 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. 1918 1919 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. 1920 1921 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1922 @*/ 1923 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1924 { 1925 PetscBool ishdf5; 1926 1927 PetscFunctionBegin; 1928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1929 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1930 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1932 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1933 if (ishdf5) { 1934 #if defined(PETSC_HAVE_HDF5) 1935 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1936 #else 1937 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1938 #endif 1939 } 1940 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1941 PetscFunctionReturn(0); 1942 } 1943 1944 /*@ 1945 DMPlexGlobalVectorView - Saves a global vector 1946 1947 Collective on DM 1948 1949 Input Parameters: 1950 + dm - The DM that represents the topology 1951 . viewer - The PetscViewer to save data with 1952 . sectiondm - The DM that contains the global section on which vec is defined 1953 - vec - The global vector to be saved 1954 1955 Level: advanced 1956 1957 Notes: 1958 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. 1959 1960 Typical calling sequence 1961 $ DMCreate(PETSC_COMM_WORLD, &dm); 1962 $ DMSetType(dm, DMPLEX); 1963 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1964 $ DMClone(dm, §iondm); 1965 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1966 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1967 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1968 $ PetscSectionSetChart(section, pStart, pEnd); 1969 $ PetscSectionSetUp(section); 1970 $ DMSetLocalSection(sectiondm, section); 1971 $ PetscSectionDestroy(§ion); 1972 $ DMGetGlobalVector(sectiondm, &vec); 1973 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1974 $ DMPlexTopologyView(dm, viewer); 1975 $ DMPlexSectionView(dm, viewer, sectiondm); 1976 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1977 $ DMRestoreGlobalVector(sectiondm, &vec); 1978 $ DMDestroy(§iondm); 1979 $ DMDestroy(&dm); 1980 1981 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1982 @*/ 1983 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1984 { 1985 PetscBool ishdf5; 1986 1987 PetscFunctionBegin; 1988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1989 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1990 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1991 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1992 /* Check consistency */ 1993 { 1994 PetscSection section; 1995 PetscBool includesConstraints; 1996 PetscInt m, m1; 1997 1998 PetscCall(VecGetLocalSize(vec, &m1)); 1999 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2000 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2001 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2002 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2003 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2004 } 2005 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2006 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2007 if (ishdf5) { 2008 #if defined(PETSC_HAVE_HDF5) 2009 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2010 #else 2011 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2012 #endif 2013 } 2014 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2015 PetscFunctionReturn(0); 2016 } 2017 2018 /*@ 2019 DMPlexLocalVectorView - Saves a local vector 2020 2021 Collective on DM 2022 2023 Input Parameters: 2024 + dm - The DM that represents the topology 2025 . viewer - The PetscViewer to save data with 2026 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2027 - vec - The local vector to be saved 2028 2029 Level: advanced 2030 2031 Notes: 2032 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. 2033 2034 Typical calling sequence 2035 $ DMCreate(PETSC_COMM_WORLD, &dm); 2036 $ DMSetType(dm, DMPLEX); 2037 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2038 $ DMClone(dm, §iondm); 2039 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2040 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2041 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2042 $ PetscSectionSetChart(section, pStart, pEnd); 2043 $ PetscSectionSetUp(section); 2044 $ DMSetLocalSection(sectiondm, section); 2045 $ DMGetLocalVector(sectiondm, &vec); 2046 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2047 $ DMPlexTopologyView(dm, viewer); 2048 $ DMPlexSectionView(dm, viewer, sectiondm); 2049 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2050 $ DMRestoreLocalVector(sectiondm, &vec); 2051 $ DMDestroy(§iondm); 2052 $ DMDestroy(&dm); 2053 2054 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2055 @*/ 2056 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2064 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2065 /* Check consistency */ 2066 { 2067 PetscSection section; 2068 PetscBool includesConstraints; 2069 PetscInt m, m1; 2070 2071 PetscCall(VecGetLocalSize(vec, &m1)); 2072 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2073 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2074 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2075 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2076 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2077 } 2078 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2079 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2080 if (ishdf5) { 2081 #if defined(PETSC_HAVE_HDF5) 2082 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2083 #else 2084 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2085 #endif 2086 } 2087 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2088 PetscFunctionReturn(0); 2089 } 2090 2091 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2092 { 2093 PetscBool ishdf5; 2094 2095 PetscFunctionBegin; 2096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2097 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2098 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2099 if (ishdf5) { 2100 #if defined(PETSC_HAVE_HDF5) 2101 PetscViewerFormat format; 2102 PetscCall(PetscViewerGetFormat(viewer, &format)); 2103 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2104 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2105 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2106 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2108 PetscFunctionReturn(0); 2109 #else 2110 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2111 #endif 2112 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2113 } 2114 2115 /*@ 2116 DMPlexTopologyLoad - Loads a topology into a DMPlex 2117 2118 Collective on DM 2119 2120 Input Parameters: 2121 + dm - The DM into which the topology is loaded 2122 - viewer - The PetscViewer for the saved topology 2123 2124 Output Parameters: 2125 . 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 2126 2127 Level: advanced 2128 2129 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2130 @*/ 2131 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2132 { 2133 PetscBool ishdf5; 2134 2135 PetscFunctionBegin; 2136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2137 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2138 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2139 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2140 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2141 if (ishdf5) { 2142 #if defined(PETSC_HAVE_HDF5) 2143 PetscViewerFormat format; 2144 PetscCall(PetscViewerGetFormat(viewer, &format)); 2145 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2146 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2147 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2148 #else 2149 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2150 #endif 2151 } 2152 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2153 PetscFunctionReturn(0); 2154 } 2155 2156 /*@ 2157 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2158 2159 Collective on DM 2160 2161 Input Parameters: 2162 + dm - The DM into which the coordinates are loaded 2163 . viewer - The PetscViewer for the saved coordinates 2164 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2165 2166 Level: advanced 2167 2168 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2169 @*/ 2170 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2171 { 2172 PetscBool ishdf5; 2173 2174 PetscFunctionBegin; 2175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2176 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2177 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2178 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2179 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2180 if (ishdf5) { 2181 #if defined(PETSC_HAVE_HDF5) 2182 PetscViewerFormat format; 2183 PetscCall(PetscViewerGetFormat(viewer, &format)); 2184 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2185 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2186 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2187 #else 2188 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2189 #endif 2190 } 2191 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2192 PetscFunctionReturn(0); 2193 } 2194 2195 /*@ 2196 DMPlexLabelsLoad - Loads labels into a DMPlex 2197 2198 Collective on DM 2199 2200 Input Parameters: 2201 + dm - The DM into which the labels are loaded 2202 . viewer - The PetscViewer for the saved labels 2203 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2204 2205 Level: advanced 2206 2207 Notes: 2208 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2209 2210 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2211 @*/ 2212 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2213 { 2214 PetscBool ishdf5; 2215 2216 PetscFunctionBegin; 2217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2218 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2219 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2220 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2221 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2222 if (ishdf5) { 2223 #if defined(PETSC_HAVE_HDF5) 2224 PetscViewerFormat format; 2225 2226 PetscCall(PetscViewerGetFormat(viewer, &format)); 2227 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2228 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2229 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2230 #else 2231 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2232 #endif 2233 } 2234 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2235 PetscFunctionReturn(0); 2236 } 2237 2238 /*@ 2239 DMPlexSectionLoad - Loads section into a DMPlex 2240 2241 Collective on DM 2242 2243 Input Parameters: 2244 + dm - The DM that represents the topology 2245 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2246 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2247 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2248 2249 Output Parameters 2250 + 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) 2251 - 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) 2252 2253 Level: advanced 2254 2255 Notes: 2256 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. 2257 2258 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. 2259 2260 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. 2261 2262 Example using 2 processes: 2263 $ NX (number of points on dm): 4 2264 $ sectionA : the on-disk section 2265 $ vecA : a vector associated with sectionA 2266 $ sectionB : sectiondm's local section constructed in this function 2267 $ vecB (local) : a vector associated with sectiondm's local section 2268 $ vecB (global) : a vector associated with sectiondm's global section 2269 $ 2270 $ rank 0 rank 1 2271 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2272 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2273 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2274 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2275 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2276 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2277 $ sectionB->atlasDof : 1 0 1 | 1 3 2278 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2279 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2280 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2281 $ 2282 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2283 2284 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2285 @*/ 2286 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2287 { 2288 PetscBool ishdf5; 2289 2290 PetscFunctionBegin; 2291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2292 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2293 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2294 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2295 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2296 if (localDofSF) PetscValidPointer(localDofSF, 6); 2297 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2298 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2299 if (ishdf5) { 2300 #if defined(PETSC_HAVE_HDF5) 2301 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2302 #else 2303 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2304 #endif 2305 } 2306 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2307 PetscFunctionReturn(0); 2308 } 2309 2310 /*@ 2311 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2312 2313 Collective on DM 2314 2315 Input Parameters: 2316 + dm - The DM that represents the topology 2317 . viewer - The PetscViewer that represents the on-disk vector data 2318 . sectiondm - The DM that contains the global section on which vec is defined 2319 . sf - The SF that migrates the on-disk vector data into vec 2320 - vec - The global vector to set values of 2321 2322 Level: advanced 2323 2324 Notes: 2325 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. 2326 2327 Typical calling sequence 2328 $ DMCreate(PETSC_COMM_WORLD, &dm); 2329 $ DMSetType(dm, DMPLEX); 2330 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2331 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2332 $ DMClone(dm, §iondm); 2333 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2334 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2335 $ DMGetGlobalVector(sectiondm, &vec); 2336 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2337 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2338 $ DMRestoreGlobalVector(sectiondm, &vec); 2339 $ PetscSFDestroy(&gsf); 2340 $ PetscSFDestroy(&sfX); 2341 $ DMDestroy(§iondm); 2342 $ DMDestroy(&dm); 2343 2344 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2345 @*/ 2346 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2347 { 2348 PetscBool ishdf5; 2349 2350 PetscFunctionBegin; 2351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2352 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2353 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2354 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2355 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2356 /* Check consistency */ 2357 { 2358 PetscSection section; 2359 PetscBool includesConstraints; 2360 PetscInt m, m1; 2361 2362 PetscCall(VecGetLocalSize(vec, &m1)); 2363 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2364 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2365 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2366 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2367 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2368 } 2369 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2370 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2371 if (ishdf5) { 2372 #if defined(PETSC_HAVE_HDF5) 2373 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2374 #else 2375 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2376 #endif 2377 } 2378 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2379 PetscFunctionReturn(0); 2380 } 2381 2382 /*@ 2383 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2384 2385 Collective on DM 2386 2387 Input Parameters: 2388 + dm - The DM that represents the topology 2389 . viewer - The PetscViewer that represents the on-disk vector data 2390 . sectiondm - The DM that contains the local section on which vec is defined 2391 . sf - The SF that migrates the on-disk vector data into vec 2392 - vec - The local vector to set values of 2393 2394 Level: advanced 2395 2396 Notes: 2397 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. 2398 2399 Typical calling sequence 2400 $ DMCreate(PETSC_COMM_WORLD, &dm); 2401 $ DMSetType(dm, DMPLEX); 2402 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2403 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2404 $ DMClone(dm, §iondm); 2405 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2406 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2407 $ DMGetLocalVector(sectiondm, &vec); 2408 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2409 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2410 $ DMRestoreLocalVector(sectiondm, &vec); 2411 $ PetscSFDestroy(&lsf); 2412 $ PetscSFDestroy(&sfX); 2413 $ DMDestroy(§iondm); 2414 $ DMDestroy(&dm); 2415 2416 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2417 @*/ 2418 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2419 { 2420 PetscBool ishdf5; 2421 2422 PetscFunctionBegin; 2423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2424 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2425 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2426 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2427 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2428 /* Check consistency */ 2429 { 2430 PetscSection section; 2431 PetscBool includesConstraints; 2432 PetscInt m, m1; 2433 2434 PetscCall(VecGetLocalSize(vec, &m1)); 2435 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2436 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2437 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2438 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2439 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2440 } 2441 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2442 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2443 if (ishdf5) { 2444 #if defined(PETSC_HAVE_HDF5) 2445 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2446 #else 2447 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2448 #endif 2449 } 2450 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2451 PetscFunctionReturn(0); 2452 } 2453 2454 PetscErrorCode DMDestroy_Plex(DM dm) 2455 { 2456 DM_Plex *mesh = (DM_Plex*) dm->data; 2457 2458 PetscFunctionBegin; 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2461 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2462 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2463 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2464 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2465 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2466 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2467 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2468 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2469 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2470 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2471 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2472 if (--mesh->refct > 0) PetscFunctionReturn(0); 2473 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2474 PetscCall(PetscFree(mesh->cones)); 2475 PetscCall(PetscFree(mesh->coneOrientations)); 2476 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2477 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2478 PetscCall(PetscFree(mesh->supports)); 2479 PetscCall(PetscFree(mesh->facesTmp)); 2480 PetscCall(PetscFree(mesh->tetgenOpts)); 2481 PetscCall(PetscFree(mesh->triangleOpts)); 2482 PetscCall(PetscFree(mesh->transformType)); 2483 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2484 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2485 PetscCall(ISDestroy(&mesh->subpointIS)); 2486 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2487 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2488 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2489 PetscCall(ISDestroy(&mesh->anchorIS)); 2490 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2491 PetscCall(PetscFree(mesh->parents)); 2492 PetscCall(PetscFree(mesh->childIDs)); 2493 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2494 PetscCall(PetscFree(mesh->children)); 2495 PetscCall(DMDestroy(&mesh->referenceTree)); 2496 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2497 PetscCall(PetscFree(mesh->neighbors)); 2498 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2499 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2500 PetscCall(PetscFree(mesh)); 2501 PetscFunctionReturn(0); 2502 } 2503 2504 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2505 { 2506 PetscSection sectionGlobal; 2507 PetscInt bs = -1, mbs; 2508 PetscInt localSize, localStart = 0; 2509 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2510 MatType mtype; 2511 ISLocalToGlobalMapping ltog; 2512 2513 PetscFunctionBegin; 2514 PetscCall(MatInitializePackage()); 2515 mtype = dm->mattype; 2516 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2517 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2518 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2519 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2520 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2521 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2522 PetscCall(MatSetType(*J, mtype)); 2523 PetscCall(MatSetFromOptions(*J)); 2524 PetscCall(MatGetBlockSize(*J, &mbs)); 2525 if (mbs > 1) bs = mbs; 2526 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2527 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2528 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2529 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2530 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2531 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2532 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2533 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2534 if (!isShell) { 2535 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2536 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2537 PetscInt pStart, pEnd, p, dof, cdof; 2538 2539 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2540 2541 PetscCall(PetscCalloc1(localSize, &pblocks)); 2542 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2543 for (p = pStart; p < pEnd; ++p) { 2544 PetscInt bdof, offset; 2545 2546 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2547 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2548 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2549 for (PetscInt i=0; i < dof - cdof; i++) 2550 pblocks[offset - localStart + i] = dof - cdof; 2551 dof = dof < 0 ? -(dof+1) : dof; 2552 bdof = cdof && (dof-cdof) ? 1 : dof; 2553 if (dof) { 2554 if (bs < 0) {bs = bdof;} 2555 else if (bs != bdof) {bs = 1;} 2556 } 2557 } 2558 /* Must have same blocksize on all procs (some might have no points) */ 2559 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2560 bsLocal[1] = bs; 2561 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2562 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2563 else bs = bsMinMax[0]; 2564 bs = PetscMax(1,bs); 2565 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2566 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2567 PetscCall(MatSetBlockSize(*J, bs)); 2568 PetscCall(MatSetUp(*J)); 2569 } else { 2570 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2571 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2572 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2573 } 2574 { // Consolidate blocks 2575 PetscInt nblocks = 0; 2576 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2577 if (pblocks[i] == 0) continue; 2578 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2579 for (PetscInt j=1; j<pblocks[i]; j++) { 2580 PetscCheck(pblocks[i+j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i+j]); 2581 } 2582 } 2583 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2584 } 2585 PetscCall(PetscFree(pblocks)); 2586 } 2587 PetscCall(MatSetDM(*J, dm)); 2588 PetscFunctionReturn(0); 2589 } 2590 2591 /*@ 2592 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2593 2594 Not collective 2595 2596 Input Parameter: 2597 . mesh - The DMPlex 2598 2599 Output Parameters: 2600 . subsection - The subdomain section 2601 2602 Level: developer 2603 2604 .seealso: 2605 @*/ 2606 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2607 { 2608 DM_Plex *mesh = (DM_Plex*) dm->data; 2609 2610 PetscFunctionBegin; 2611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2612 if (!mesh->subdomainSection) { 2613 PetscSection section; 2614 PetscSF sf; 2615 2616 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2617 PetscCall(DMGetLocalSection(dm,§ion)); 2618 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2619 PetscCall(PetscSFDestroy(&sf)); 2620 } 2621 *subsection = mesh->subdomainSection; 2622 PetscFunctionReturn(0); 2623 } 2624 2625 /*@ 2626 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2627 2628 Not collective 2629 2630 Input Parameter: 2631 . mesh - The DMPlex 2632 2633 Output Parameters: 2634 + pStart - The first mesh point 2635 - pEnd - The upper bound for mesh points 2636 2637 Level: beginner 2638 2639 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2640 @*/ 2641 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2642 { 2643 DM_Plex *mesh = (DM_Plex*) dm->data; 2644 2645 PetscFunctionBegin; 2646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2647 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2648 PetscFunctionReturn(0); 2649 } 2650 2651 /*@ 2652 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2653 2654 Not collective 2655 2656 Input Parameters: 2657 + mesh - The DMPlex 2658 . pStart - The first mesh point 2659 - pEnd - The upper bound for mesh points 2660 2661 Output Parameters: 2662 2663 Level: beginner 2664 2665 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2666 @*/ 2667 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2668 { 2669 DM_Plex *mesh = (DM_Plex*) dm->data; 2670 2671 PetscFunctionBegin; 2672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2673 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2674 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2675 PetscFunctionReturn(0); 2676 } 2677 2678 /*@ 2679 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2680 2681 Not collective 2682 2683 Input Parameters: 2684 + mesh - The DMPlex 2685 - p - The point, which must lie in the chart set with DMPlexSetChart() 2686 2687 Output Parameter: 2688 . size - The cone size for point p 2689 2690 Level: beginner 2691 2692 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2693 @*/ 2694 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2695 { 2696 DM_Plex *mesh = (DM_Plex*) dm->data; 2697 2698 PetscFunctionBegin; 2699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2700 PetscValidIntPointer(size, 3); 2701 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2702 PetscFunctionReturn(0); 2703 } 2704 2705 /*@ 2706 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2707 2708 Not collective 2709 2710 Input Parameters: 2711 + mesh - The DMPlex 2712 . p - The point, which must lie in the chart set with DMPlexSetChart() 2713 - size - The cone size for point p 2714 2715 Output Parameter: 2716 2717 Note: 2718 This should be called after DMPlexSetChart(). 2719 2720 Level: beginner 2721 2722 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2723 @*/ 2724 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2725 { 2726 DM_Plex *mesh = (DM_Plex*) dm->data; 2727 2728 PetscFunctionBegin; 2729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2730 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2731 PetscFunctionReturn(0); 2732 } 2733 2734 /*@ 2735 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2736 2737 Not collective 2738 2739 Input Parameters: 2740 + mesh - The DMPlex 2741 . p - The point, which must lie in the chart set with DMPlexSetChart() 2742 - size - The additional cone size for point p 2743 2744 Output Parameter: 2745 2746 Note: 2747 This should be called after DMPlexSetChart(). 2748 2749 Level: beginner 2750 2751 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2752 @*/ 2753 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2754 { 2755 DM_Plex *mesh = (DM_Plex*) dm->data; 2756 PetscFunctionBegin; 2757 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2758 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2759 PetscFunctionReturn(0); 2760 } 2761 2762 /*@C 2763 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2764 2765 Not collective 2766 2767 Input Parameters: 2768 + dm - The DMPlex 2769 - p - The point, which must lie in the chart set with DMPlexSetChart() 2770 2771 Output Parameter: 2772 . cone - An array of points which are on the in-edges for point p 2773 2774 Level: beginner 2775 2776 Fortran Notes: 2777 Since it returns an array, this routine is only available in Fortran 90, and you must 2778 include petsc.h90 in your code. 2779 You must also call DMPlexRestoreCone() after you finish using the returned array. 2780 DMPlexRestoreCone() is not needed/available in C. 2781 2782 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2783 @*/ 2784 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2785 { 2786 DM_Plex *mesh = (DM_Plex*) dm->data; 2787 PetscInt off; 2788 2789 PetscFunctionBegin; 2790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2791 PetscValidPointer(cone, 3); 2792 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2793 *cone = &mesh->cones[off]; 2794 PetscFunctionReturn(0); 2795 } 2796 2797 /*@C 2798 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2799 2800 Not collective 2801 2802 Input Parameters: 2803 + dm - The DMPlex 2804 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2805 2806 Output Parameters: 2807 + pConesSection - PetscSection describing the layout of pCones 2808 - pCones - An array of points which are on the in-edges for the point set p 2809 2810 Level: intermediate 2811 2812 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2813 @*/ 2814 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2815 { 2816 PetscSection cs, newcs; 2817 PetscInt *cones; 2818 PetscInt *newarr=NULL; 2819 PetscInt n; 2820 2821 PetscFunctionBegin; 2822 PetscCall(DMPlexGetCones(dm, &cones)); 2823 PetscCall(DMPlexGetConeSection(dm, &cs)); 2824 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2825 if (pConesSection) *pConesSection = newcs; 2826 if (pCones) { 2827 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2828 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2829 } 2830 PetscFunctionReturn(0); 2831 } 2832 2833 /*@ 2834 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2835 2836 Not collective 2837 2838 Input Parameters: 2839 + dm - The DMPlex 2840 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2841 2842 Output Parameter: 2843 . expandedPoints - An array of vertices recursively expanded from input points 2844 2845 Level: advanced 2846 2847 Notes: 2848 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2849 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2850 2851 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2852 @*/ 2853 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2854 { 2855 IS *expandedPointsAll; 2856 PetscInt depth; 2857 2858 PetscFunctionBegin; 2859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2860 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2861 PetscValidPointer(expandedPoints, 3); 2862 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2863 *expandedPoints = expandedPointsAll[0]; 2864 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2865 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2866 PetscFunctionReturn(0); 2867 } 2868 2869 /*@ 2870 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). 2871 2872 Not collective 2873 2874 Input Parameters: 2875 + dm - The DMPlex 2876 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2877 2878 Output Parameters: 2879 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2880 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2881 - sections - (optional) An array of sections which describe mappings from points to their cone points 2882 2883 Level: advanced 2884 2885 Notes: 2886 Like DMPlexGetConeTuple() but recursive. 2887 2888 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. 2889 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2890 2891 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: 2892 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2893 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2894 2895 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2896 @*/ 2897 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2898 { 2899 const PetscInt *arr0=NULL, *cone=NULL; 2900 PetscInt *arr=NULL, *newarr=NULL; 2901 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2902 IS *expandedPoints_; 2903 PetscSection *sections_; 2904 2905 PetscFunctionBegin; 2906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2907 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2908 if (depth) PetscValidIntPointer(depth, 3); 2909 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2910 if (sections) PetscValidPointer(sections, 5); 2911 PetscCall(ISGetLocalSize(points, &n)); 2912 PetscCall(ISGetIndices(points, &arr0)); 2913 PetscCall(DMPlexGetDepth(dm, &depth_)); 2914 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2915 PetscCall(PetscCalloc1(depth_, §ions_)); 2916 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2917 for (d=depth_-1; d>=0; d--) { 2918 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2919 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2920 for (i=0; i<n; i++) { 2921 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2922 if (arr[i] >= start && arr[i] < end) { 2923 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2924 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2925 } else { 2926 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2927 } 2928 } 2929 PetscCall(PetscSectionSetUp(sections_[d])); 2930 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2931 PetscCall(PetscMalloc1(newn, &newarr)); 2932 for (i=0; i<n; i++) { 2933 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2934 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2935 if (cn > 1) { 2936 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2937 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2938 } else { 2939 newarr[co] = arr[i]; 2940 } 2941 } 2942 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2943 arr = newarr; 2944 n = newn; 2945 } 2946 PetscCall(ISRestoreIndices(points, &arr0)); 2947 *depth = depth_; 2948 if (expandedPoints) *expandedPoints = expandedPoints_; 2949 else { 2950 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2951 PetscCall(PetscFree(expandedPoints_)); 2952 } 2953 if (sections) *sections = sections_; 2954 else { 2955 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2956 PetscCall(PetscFree(sections_)); 2957 } 2958 PetscFunctionReturn(0); 2959 } 2960 2961 /*@ 2962 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2963 2964 Not collective 2965 2966 Input Parameters: 2967 + dm - The DMPlex 2968 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2969 2970 Output Parameters: 2971 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2972 . expandedPoints - (optional) An array of recursively expanded cones 2973 - sections - (optional) An array of sections which describe mappings from points to their cone points 2974 2975 Level: advanced 2976 2977 Notes: 2978 See DMPlexGetConeRecursive() for details. 2979 2980 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2981 @*/ 2982 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2983 { 2984 PetscInt d, depth_; 2985 2986 PetscFunctionBegin; 2987 PetscCall(DMPlexGetDepth(dm, &depth_)); 2988 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2989 if (depth) *depth = 0; 2990 if (expandedPoints) { 2991 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2992 PetscCall(PetscFree(*expandedPoints)); 2993 } 2994 if (sections) { 2995 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2996 PetscCall(PetscFree(*sections)); 2997 } 2998 PetscFunctionReturn(0); 2999 } 3000 3001 /*@ 3002 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 3003 3004 Not collective 3005 3006 Input Parameters: 3007 + mesh - The DMPlex 3008 . p - The point, which must lie in the chart set with DMPlexSetChart() 3009 - cone - An array of points which are on the in-edges for point p 3010 3011 Output Parameter: 3012 3013 Note: 3014 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3015 3016 Level: beginner 3017 3018 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3019 @*/ 3020 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3021 { 3022 DM_Plex *mesh = (DM_Plex*) dm->data; 3023 PetscInt pStart, pEnd; 3024 PetscInt dof, off, c; 3025 3026 PetscFunctionBegin; 3027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3028 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3029 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3030 if (dof) PetscValidIntPointer(cone, 3); 3031 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3032 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3033 for (c = 0; c < dof; ++c) { 3034 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3035 mesh->cones[off+c] = cone[c]; 3036 } 3037 PetscFunctionReturn(0); 3038 } 3039 3040 /*@C 3041 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3042 3043 Not collective 3044 3045 Input Parameters: 3046 + mesh - The DMPlex 3047 - p - The point, which must lie in the chart set with DMPlexSetChart() 3048 3049 Output Parameter: 3050 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3051 integer giving the prescription for cone traversal. 3052 3053 Level: beginner 3054 3055 Notes: 3056 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3057 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3058 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3059 with the identity. 3060 3061 Fortran Notes: 3062 Since it returns an array, this routine is only available in Fortran 90, and you must 3063 include petsc.h90 in your code. 3064 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3065 DMPlexRestoreConeOrientation() is not needed/available in C. 3066 3067 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3068 @*/ 3069 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3070 { 3071 DM_Plex *mesh = (DM_Plex*) dm->data; 3072 PetscInt off; 3073 3074 PetscFunctionBegin; 3075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3076 if (PetscDefined(USE_DEBUG)) { 3077 PetscInt dof; 3078 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3079 if (dof) PetscValidPointer(coneOrientation, 3); 3080 } 3081 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3082 3083 *coneOrientation = &mesh->coneOrientations[off]; 3084 PetscFunctionReturn(0); 3085 } 3086 3087 /*@ 3088 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3089 3090 Not collective 3091 3092 Input Parameters: 3093 + mesh - The DMPlex 3094 . p - The point, which must lie in the chart set with DMPlexSetChart() 3095 - coneOrientation - An array of orientations 3096 Output Parameter: 3097 3098 Notes: 3099 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3100 3101 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3102 3103 Level: beginner 3104 3105 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3106 @*/ 3107 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3108 { 3109 DM_Plex *mesh = (DM_Plex*) dm->data; 3110 PetscInt pStart, pEnd; 3111 PetscInt dof, off, c; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3116 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3117 if (dof) PetscValidIntPointer(coneOrientation, 3); 3118 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3119 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3120 for (c = 0; c < dof; ++c) { 3121 PetscInt cdof, o = coneOrientation[c]; 3122 3123 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3124 PetscCheck(!o || (o >= -(cdof+1) && o < cdof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof+1), cdof); 3125 mesh->coneOrientations[off+c] = o; 3126 } 3127 PetscFunctionReturn(0); 3128 } 3129 3130 /*@ 3131 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3132 3133 Not collective 3134 3135 Input Parameters: 3136 + mesh - The DMPlex 3137 . p - The point, which must lie in the chart set with DMPlexSetChart() 3138 . conePos - The local index in the cone where the point should be put 3139 - conePoint - The mesh point to insert 3140 3141 Level: beginner 3142 3143 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3144 @*/ 3145 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3146 { 3147 DM_Plex *mesh = (DM_Plex*) dm->data; 3148 PetscInt pStart, pEnd; 3149 PetscInt dof, off; 3150 3151 PetscFunctionBegin; 3152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3153 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3154 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3155 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3156 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3157 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3158 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3159 mesh->cones[off+conePos] = conePoint; 3160 PetscFunctionReturn(0); 3161 } 3162 3163 /*@ 3164 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3165 3166 Not collective 3167 3168 Input Parameters: 3169 + mesh - The DMPlex 3170 . p - The point, which must lie in the chart set with DMPlexSetChart() 3171 . conePos - The local index in the cone where the point should be put 3172 - coneOrientation - The point orientation to insert 3173 3174 Level: beginner 3175 3176 Notes: 3177 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3178 3179 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3180 @*/ 3181 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3182 { 3183 DM_Plex *mesh = (DM_Plex*) dm->data; 3184 PetscInt pStart, pEnd; 3185 PetscInt dof, off; 3186 3187 PetscFunctionBegin; 3188 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3189 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3190 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3191 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3192 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3193 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3194 mesh->coneOrientations[off+conePos] = coneOrientation; 3195 PetscFunctionReturn(0); 3196 } 3197 3198 /*@ 3199 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3200 3201 Not collective 3202 3203 Input Parameters: 3204 + mesh - The DMPlex 3205 - p - The point, which must lie in the chart set with DMPlexSetChart() 3206 3207 Output Parameter: 3208 . size - The support size for point p 3209 3210 Level: beginner 3211 3212 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3213 @*/ 3214 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3215 { 3216 DM_Plex *mesh = (DM_Plex*) dm->data; 3217 3218 PetscFunctionBegin; 3219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3220 PetscValidIntPointer(size, 3); 3221 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3222 PetscFunctionReturn(0); 3223 } 3224 3225 /*@ 3226 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3227 3228 Not collective 3229 3230 Input Parameters: 3231 + mesh - The DMPlex 3232 . p - The point, which must lie in the chart set with DMPlexSetChart() 3233 - size - The support size for point p 3234 3235 Output Parameter: 3236 3237 Note: 3238 This should be called after DMPlexSetChart(). 3239 3240 Level: beginner 3241 3242 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3243 @*/ 3244 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3245 { 3246 DM_Plex *mesh = (DM_Plex*) dm->data; 3247 3248 PetscFunctionBegin; 3249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3250 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3251 PetscFunctionReturn(0); 3252 } 3253 3254 /*@C 3255 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3256 3257 Not collective 3258 3259 Input Parameters: 3260 + mesh - The DMPlex 3261 - p - The point, which must lie in the chart set with DMPlexSetChart() 3262 3263 Output Parameter: 3264 . support - An array of points which are on the out-edges for point p 3265 3266 Level: beginner 3267 3268 Fortran Notes: 3269 Since it returns an array, this routine is only available in Fortran 90, and you must 3270 include petsc.h90 in your code. 3271 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3272 DMPlexRestoreSupport() is not needed/available in C. 3273 3274 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3275 @*/ 3276 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3277 { 3278 DM_Plex *mesh = (DM_Plex*) dm->data; 3279 PetscInt off; 3280 3281 PetscFunctionBegin; 3282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3283 PetscValidPointer(support, 3); 3284 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3285 *support = &mesh->supports[off]; 3286 PetscFunctionReturn(0); 3287 } 3288 3289 /*@ 3290 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3291 3292 Not collective 3293 3294 Input Parameters: 3295 + mesh - The DMPlex 3296 . p - The point, which must lie in the chart set with DMPlexSetChart() 3297 - support - An array of points which are on the out-edges for point p 3298 3299 Output Parameter: 3300 3301 Note: 3302 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3303 3304 Level: beginner 3305 3306 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3307 @*/ 3308 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3309 { 3310 DM_Plex *mesh = (DM_Plex*) dm->data; 3311 PetscInt pStart, pEnd; 3312 PetscInt dof, off, c; 3313 3314 PetscFunctionBegin; 3315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3316 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3317 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3318 if (dof) PetscValidIntPointer(support, 3); 3319 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3320 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3321 for (c = 0; c < dof; ++c) { 3322 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3323 mesh->supports[off+c] = support[c]; 3324 } 3325 PetscFunctionReturn(0); 3326 } 3327 3328 /*@ 3329 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3330 3331 Not collective 3332 3333 Input Parameters: 3334 + mesh - The DMPlex 3335 . p - The point, which must lie in the chart set with DMPlexSetChart() 3336 . supportPos - The local index in the cone where the point should be put 3337 - supportPoint - The mesh point to insert 3338 3339 Level: beginner 3340 3341 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3342 @*/ 3343 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3344 { 3345 DM_Plex *mesh = (DM_Plex*) dm->data; 3346 PetscInt pStart, pEnd; 3347 PetscInt dof, off; 3348 3349 PetscFunctionBegin; 3350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3351 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3352 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3353 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3354 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3355 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3356 PetscCheck(supportPos < dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3357 mesh->supports[off+supportPos] = supportPoint; 3358 PetscFunctionReturn(0); 3359 } 3360 3361 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3362 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3363 { 3364 switch (ct) { 3365 case DM_POLYTOPE_SEGMENT: 3366 if (o == -1) return -2; 3367 break; 3368 case DM_POLYTOPE_TRIANGLE: 3369 if (o == -3) return -1; 3370 if (o == -2) return -3; 3371 if (o == -1) return -2; 3372 break; 3373 case DM_POLYTOPE_QUADRILATERAL: 3374 if (o == -4) return -2; 3375 if (o == -3) return -1; 3376 if (o == -2) return -4; 3377 if (o == -1) return -3; 3378 break; 3379 default: return o; 3380 } 3381 return o; 3382 } 3383 3384 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3385 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3386 { 3387 switch (ct) { 3388 case DM_POLYTOPE_SEGMENT: 3389 if ((o == -2) || (o == 1)) return -1; 3390 if (o == -1) return 0; 3391 break; 3392 case DM_POLYTOPE_TRIANGLE: 3393 if (o == -3) return -2; 3394 if (o == -2) return -1; 3395 if (o == -1) return -3; 3396 break; 3397 case DM_POLYTOPE_QUADRILATERAL: 3398 if (o == -4) return -2; 3399 if (o == -3) return -1; 3400 if (o == -2) return -4; 3401 if (o == -1) return -3; 3402 break; 3403 default: return o; 3404 } 3405 return o; 3406 } 3407 3408 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3409 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3410 { 3411 PetscInt pStart, pEnd, p; 3412 3413 PetscFunctionBegin; 3414 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3415 for (p = pStart; p < pEnd; ++p) { 3416 const PetscInt *cone, *ornt; 3417 PetscInt coneSize, c; 3418 3419 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3420 PetscCall(DMPlexGetCone(dm, p, &cone)); 3421 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3422 for (c = 0; c < coneSize; ++c) { 3423 DMPolytopeType ct; 3424 const PetscInt o = ornt[c]; 3425 3426 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3427 switch (ct) { 3428 case DM_POLYTOPE_SEGMENT: 3429 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3430 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3431 break; 3432 case DM_POLYTOPE_TRIANGLE: 3433 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3434 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3435 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3436 break; 3437 case DM_POLYTOPE_QUADRILATERAL: 3438 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3439 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3440 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3441 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3442 break; 3443 default: break; 3444 } 3445 } 3446 } 3447 PetscFunctionReturn(0); 3448 } 3449 3450 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3451 { 3452 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3453 PetscInt *closure; 3454 const PetscInt *tmp = NULL, *tmpO = NULL; 3455 PetscInt off = 0, tmpSize, t; 3456 3457 PetscFunctionBeginHot; 3458 if (ornt) { 3459 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3460 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3461 } 3462 if (*points) { 3463 closure = *points; 3464 } else { 3465 PetscInt maxConeSize, maxSupportSize; 3466 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3467 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3468 } 3469 if (useCone) { 3470 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3471 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3472 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3473 } else { 3474 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3475 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3476 } 3477 if (ct == DM_POLYTOPE_UNKNOWN) { 3478 closure[off++] = p; 3479 closure[off++] = 0; 3480 for (t = 0; t < tmpSize; ++t) { 3481 closure[off++] = tmp[t]; 3482 closure[off++] = tmpO ? tmpO[t] : 0; 3483 } 3484 } else { 3485 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3486 3487 /* We assume that cells with a valid type have faces with a valid type */ 3488 closure[off++] = p; 3489 closure[off++] = ornt; 3490 for (t = 0; t < tmpSize; ++t) { 3491 DMPolytopeType ft; 3492 3493 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3494 closure[off++] = tmp[arr[t]]; 3495 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3496 } 3497 } 3498 if (numPoints) *numPoints = tmpSize+1; 3499 if (points) *points = closure; 3500 PetscFunctionReturn(0); 3501 } 3502 3503 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3504 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3505 { 3506 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3507 const PetscInt *cone, *ornt; 3508 PetscInt *pts, *closure = NULL; 3509 DMPolytopeType ft; 3510 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3511 PetscInt dim, coneSize, c, d, clSize, cl; 3512 3513 PetscFunctionBeginHot; 3514 PetscCall(DMGetDimension(dm, &dim)); 3515 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3516 PetscCall(DMPlexGetCone(dm, point, &cone)); 3517 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3518 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3519 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3520 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3521 maxSize = PetscMax(coneSeries, supportSeries); 3522 if (*points) {pts = *points;} 3523 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3524 c = 0; 3525 pts[c++] = point; 3526 pts[c++] = o; 3527 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3528 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3529 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3530 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3531 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3532 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3533 for (d = 2; d < coneSize; ++d) { 3534 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3535 pts[c++] = cone[arr[d*2+0]]; 3536 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3537 } 3538 if (dim >= 3) { 3539 for (d = 2; d < coneSize; ++d) { 3540 const PetscInt fpoint = cone[arr[d*2+0]]; 3541 const PetscInt *fcone, *fornt; 3542 PetscInt fconeSize, fc, i; 3543 3544 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3545 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3546 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3547 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3548 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3549 for (fc = 0; fc < fconeSize; ++fc) { 3550 const PetscInt cp = fcone[farr[fc*2+0]]; 3551 const PetscInt co = farr[fc*2+1]; 3552 3553 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3554 if (i == c) { 3555 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3556 pts[c++] = cp; 3557 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3558 } 3559 } 3560 } 3561 } 3562 *numPoints = c/2; 3563 *points = pts; 3564 PetscFunctionReturn(0); 3565 } 3566 3567 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3568 { 3569 DMPolytopeType ct; 3570 PetscInt *closure, *fifo; 3571 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3572 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3573 PetscInt depth, maxSize; 3574 3575 PetscFunctionBeginHot; 3576 PetscCall(DMPlexGetDepth(dm, &depth)); 3577 if (depth == 1) { 3578 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3579 PetscFunctionReturn(0); 3580 } 3581 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3582 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3583 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3584 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3585 PetscFunctionReturn(0); 3586 } 3587 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3588 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3589 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3590 maxSize = PetscMax(coneSeries, supportSeries); 3591 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3592 if (*points) {closure = *points;} 3593 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3594 closure[closureSize++] = p; 3595 closure[closureSize++] = ornt; 3596 fifo[fifoSize++] = p; 3597 fifo[fifoSize++] = ornt; 3598 fifo[fifoSize++] = ct; 3599 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3600 while (fifoSize - fifoStart) { 3601 const PetscInt q = fifo[fifoStart++]; 3602 const PetscInt o = fifo[fifoStart++]; 3603 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3604 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3605 const PetscInt *tmp, *tmpO; 3606 PetscInt tmpSize, t; 3607 3608 if (PetscDefined(USE_DEBUG)) { 3609 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3610 PetscCheck(!o || !(o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3611 } 3612 if (useCone) { 3613 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3614 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3615 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3616 } else { 3617 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3618 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3619 tmpO = NULL; 3620 } 3621 for (t = 0; t < tmpSize; ++t) { 3622 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3623 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3624 const PetscInt cp = tmp[ip]; 3625 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3626 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3627 PetscInt c; 3628 3629 /* Check for duplicate */ 3630 for (c = 0; c < closureSize; c += 2) { 3631 if (closure[c] == cp) break; 3632 } 3633 if (c == closureSize) { 3634 closure[closureSize++] = cp; 3635 closure[closureSize++] = co; 3636 fifo[fifoSize++] = cp; 3637 fifo[fifoSize++] = co; 3638 fifo[fifoSize++] = ct; 3639 } 3640 } 3641 } 3642 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3643 if (numPoints) *numPoints = closureSize/2; 3644 if (points) *points = closure; 3645 PetscFunctionReturn(0); 3646 } 3647 3648 /*@C 3649 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3650 3651 Not collective 3652 3653 Input Parameters: 3654 + dm - The DMPlex 3655 . p - The mesh point 3656 - useCone - PETSC_TRUE for the closure, otherwise return the star 3657 3658 Input/Output Parameter: 3659 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3660 if NULL on input, internal storage will be returned, otherwise the provided array is used 3661 3662 Output Parameter: 3663 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3664 3665 Note: 3666 If using internal storage (points is NULL on input), each call overwrites the last output. 3667 3668 Fortran Note: 3669 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3670 3671 Level: beginner 3672 3673 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3674 @*/ 3675 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3676 { 3677 PetscFunctionBeginHot; 3678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3679 if (numPoints) PetscValidIntPointer(numPoints, 4); 3680 if (points) PetscValidPointer(points, 5); 3681 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3682 PetscFunctionReturn(0); 3683 } 3684 3685 /*@C 3686 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3687 3688 Not collective 3689 3690 Input Parameters: 3691 + dm - The DMPlex 3692 . p - The mesh point 3693 . useCone - PETSC_TRUE for the closure, otherwise return the star 3694 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3695 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3696 3697 Note: 3698 If not using internal storage (points is not NULL on input), this call is unnecessary 3699 3700 Level: beginner 3701 3702 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3703 @*/ 3704 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3705 { 3706 PetscFunctionBeginHot; 3707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3708 if (numPoints) *numPoints = 0; 3709 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3710 PetscFunctionReturn(0); 3711 } 3712 3713 /*@ 3714 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3715 3716 Not collective 3717 3718 Input Parameter: 3719 . mesh - The DMPlex 3720 3721 Output Parameters: 3722 + maxConeSize - The maximum number of in-edges 3723 - maxSupportSize - The maximum number of out-edges 3724 3725 Level: beginner 3726 3727 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3728 @*/ 3729 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3730 { 3731 DM_Plex *mesh = (DM_Plex*) dm->data; 3732 3733 PetscFunctionBegin; 3734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3735 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3736 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3737 PetscFunctionReturn(0); 3738 } 3739 3740 PetscErrorCode DMSetUp_Plex(DM dm) 3741 { 3742 DM_Plex *mesh = (DM_Plex*) dm->data; 3743 PetscInt size, maxSupportSize; 3744 3745 PetscFunctionBegin; 3746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3747 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3748 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3749 PetscCall(PetscMalloc1(size, &mesh->cones)); 3750 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3751 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3752 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3753 if (maxSupportSize) { 3754 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3755 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3756 PetscCall(PetscMalloc1(size, &mesh->supports)); 3757 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3758 } 3759 PetscFunctionReturn(0); 3760 } 3761 3762 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3763 { 3764 PetscFunctionBegin; 3765 if (subdm) PetscCall(DMClone(dm, subdm)); 3766 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3767 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3768 if (dm->useNatural && dm->sfMigration) { 3769 PetscSF sfNatural; 3770 3771 (*subdm)->sfMigration = dm->sfMigration; 3772 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3773 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3774 (*subdm)->sfNatural = sfNatural; 3775 } 3776 PetscFunctionReturn(0); 3777 } 3778 3779 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3780 { 3781 PetscInt i = 0; 3782 3783 PetscFunctionBegin; 3784 PetscCall(DMClone(dms[0], superdm)); 3785 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3786 (*superdm)->useNatural = PETSC_FALSE; 3787 for (i = 0; i < len; i++) { 3788 if (dms[i]->useNatural && dms[i]->sfMigration) { 3789 PetscSF sfNatural; 3790 3791 (*superdm)->sfMigration = dms[i]->sfMigration; 3792 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3793 (*superdm)->useNatural = PETSC_TRUE; 3794 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3795 (*superdm)->sfNatural = sfNatural; 3796 break; 3797 } 3798 } 3799 PetscFunctionReturn(0); 3800 } 3801 3802 /*@ 3803 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3804 3805 Not collective 3806 3807 Input Parameter: 3808 . mesh - The DMPlex 3809 3810 Output Parameter: 3811 3812 Note: 3813 This should be called after all calls to DMPlexSetCone() 3814 3815 Level: beginner 3816 3817 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3818 @*/ 3819 PetscErrorCode DMPlexSymmetrize(DM dm) 3820 { 3821 DM_Plex *mesh = (DM_Plex*) dm->data; 3822 PetscInt *offsets; 3823 PetscInt supportSize; 3824 PetscInt pStart, pEnd, p; 3825 3826 PetscFunctionBegin; 3827 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3828 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3829 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3830 /* Calculate support sizes */ 3831 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3832 for (p = pStart; p < pEnd; ++p) { 3833 PetscInt dof, off, c; 3834 3835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3837 for (c = off; c < off+dof; ++c) { 3838 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3839 } 3840 } 3841 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3842 /* Calculate supports */ 3843 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3844 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3845 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3846 for (p = pStart; p < pEnd; ++p) { 3847 PetscInt dof, off, c; 3848 3849 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3850 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3851 for (c = off; c < off+dof; ++c) { 3852 const PetscInt q = mesh->cones[c]; 3853 PetscInt offS; 3854 3855 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3856 3857 mesh->supports[offS+offsets[q]] = p; 3858 ++offsets[q]; 3859 } 3860 } 3861 PetscCall(PetscFree(offsets)); 3862 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3863 PetscFunctionReturn(0); 3864 } 3865 3866 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3867 { 3868 IS stratumIS; 3869 3870 PetscFunctionBegin; 3871 if (pStart >= pEnd) PetscFunctionReturn(0); 3872 if (PetscDefined(USE_DEBUG)) { 3873 PetscInt qStart, qEnd, numLevels, level; 3874 PetscBool overlap = PETSC_FALSE; 3875 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3876 for (level = 0; level < numLevels; level++) { 3877 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3878 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3879 } 3880 PetscCheck(!overlap,PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 3881 } 3882 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3883 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3884 PetscCall(ISDestroy(&stratumIS)); 3885 PetscFunctionReturn(0); 3886 } 3887 3888 /*@ 3889 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3890 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3891 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3892 the DAG. 3893 3894 Collective on dm 3895 3896 Input Parameter: 3897 . mesh - The DMPlex 3898 3899 Output Parameter: 3900 3901 Notes: 3902 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3903 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3904 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3905 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3906 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3907 3908 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3909 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3910 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 3911 to interpolate only that one (e0), so that 3912 $ cone(c0) = {e0, v2} 3913 $ cone(e0) = {v0, v1} 3914 If DMPlexStratify() is run on this mesh, it will give depths 3915 $ depth 0 = {v0, v1, v2} 3916 $ depth 1 = {e0, c0} 3917 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3918 3919 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3920 3921 Level: beginner 3922 3923 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3924 @*/ 3925 PetscErrorCode DMPlexStratify(DM dm) 3926 { 3927 DM_Plex *mesh = (DM_Plex*) dm->data; 3928 DMLabel label; 3929 PetscInt pStart, pEnd, p; 3930 PetscInt numRoots = 0, numLeaves = 0; 3931 3932 PetscFunctionBegin; 3933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3934 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3935 3936 /* Create depth label */ 3937 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3938 PetscCall(DMCreateLabel(dm, "depth")); 3939 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3940 3941 { 3942 /* Initialize roots and count leaves */ 3943 PetscInt sMin = PETSC_MAX_INT; 3944 PetscInt sMax = PETSC_MIN_INT; 3945 PetscInt coneSize, supportSize; 3946 3947 for (p = pStart; p < pEnd; ++p) { 3948 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3949 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3950 if (!coneSize && supportSize) { 3951 sMin = PetscMin(p, sMin); 3952 sMax = PetscMax(p, sMax); 3953 ++numRoots; 3954 } else if (!supportSize && coneSize) { 3955 ++numLeaves; 3956 } else if (!supportSize && !coneSize) { 3957 /* Isolated points */ 3958 sMin = PetscMin(p, sMin); 3959 sMax = PetscMax(p, sMax); 3960 } 3961 } 3962 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3963 } 3964 3965 if (numRoots + numLeaves == (pEnd - pStart)) { 3966 PetscInt sMin = PETSC_MAX_INT; 3967 PetscInt sMax = PETSC_MIN_INT; 3968 PetscInt coneSize, supportSize; 3969 3970 for (p = pStart; p < pEnd; ++p) { 3971 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3972 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3973 if (!supportSize && coneSize) { 3974 sMin = PetscMin(p, sMin); 3975 sMax = PetscMax(p, sMax); 3976 } 3977 } 3978 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3979 } else { 3980 PetscInt level = 0; 3981 PetscInt qStart, qEnd, q; 3982 3983 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3984 while (qEnd > qStart) { 3985 PetscInt sMin = PETSC_MAX_INT; 3986 PetscInt sMax = PETSC_MIN_INT; 3987 3988 for (q = qStart; q < qEnd; ++q) { 3989 const PetscInt *support; 3990 PetscInt supportSize, s; 3991 3992 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3993 PetscCall(DMPlexGetSupport(dm, q, &support)); 3994 for (s = 0; s < supportSize; ++s) { 3995 sMin = PetscMin(support[s], sMin); 3996 sMax = PetscMax(support[s], sMax); 3997 } 3998 } 3999 PetscCall(DMLabelGetNumValues(label, &level)); 4000 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4001 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4002 } 4003 } 4004 { /* just in case there is an empty process */ 4005 PetscInt numValues, maxValues = 0, v; 4006 4007 PetscCall(DMLabelGetNumValues(label, &numValues)); 4008 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4009 for (v = numValues; v < maxValues; v++) { 4010 PetscCall(DMLabelAddStratum(label, v)); 4011 } 4012 } 4013 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4014 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4015 PetscFunctionReturn(0); 4016 } 4017 4018 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4019 { 4020 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4021 PetscInt dim, depth, pheight, coneSize; 4022 4023 PetscFunctionBeginHot; 4024 PetscCall(DMGetDimension(dm, &dim)); 4025 PetscCall(DMPlexGetDepth(dm, &depth)); 4026 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4027 pheight = depth - pdepth; 4028 if (depth <= 1) { 4029 switch (pdepth) { 4030 case 0: ct = DM_POLYTOPE_POINT;break; 4031 case 1: 4032 switch (coneSize) { 4033 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4034 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4035 case 4: 4036 switch (dim) { 4037 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4038 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4039 default: break; 4040 } 4041 break; 4042 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4043 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4044 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4045 default: break; 4046 } 4047 } 4048 } else { 4049 if (pdepth == 0) { 4050 ct = DM_POLYTOPE_POINT; 4051 } else if (pheight == 0) { 4052 switch (dim) { 4053 case 1: 4054 switch (coneSize) { 4055 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4056 default: break; 4057 } 4058 break; 4059 case 2: 4060 switch (coneSize) { 4061 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4062 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4063 default: break; 4064 } 4065 break; 4066 case 3: 4067 switch (coneSize) { 4068 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4069 case 5: 4070 { 4071 const PetscInt *cone; 4072 PetscInt faceConeSize; 4073 4074 PetscCall(DMPlexGetCone(dm, p, &cone)); 4075 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4076 switch (faceConeSize) { 4077 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4078 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4079 } 4080 } 4081 break; 4082 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4083 default: break; 4084 } 4085 break; 4086 default: break; 4087 } 4088 } else if (pheight > 0) { 4089 switch (coneSize) { 4090 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4091 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4092 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4093 default: break; 4094 } 4095 } 4096 } 4097 *pt = ct; 4098 PetscFunctionReturn(0); 4099 } 4100 4101 /*@ 4102 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4103 4104 Collective on dm 4105 4106 Input Parameter: 4107 . mesh - The DMPlex 4108 4109 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4110 4111 Level: developer 4112 4113 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4114 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4115 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4116 4117 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4118 @*/ 4119 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4120 { 4121 DM_Plex *mesh; 4122 DMLabel ctLabel; 4123 PetscInt pStart, pEnd, p; 4124 4125 PetscFunctionBegin; 4126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4127 mesh = (DM_Plex *) dm->data; 4128 PetscCall(DMCreateLabel(dm, "celltype")); 4129 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4130 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4131 for (p = pStart; p < pEnd; ++p) { 4132 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4133 PetscInt pdepth; 4134 4135 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4136 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4137 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4138 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4139 } 4140 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4141 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4142 PetscFunctionReturn(0); 4143 } 4144 4145 /*@C 4146 DMPlexGetJoin - Get an array for the join of the set of points 4147 4148 Not Collective 4149 4150 Input Parameters: 4151 + dm - The DMPlex object 4152 . numPoints - The number of input points for the join 4153 - points - The input points 4154 4155 Output Parameters: 4156 + numCoveredPoints - The number of points in the join 4157 - coveredPoints - The points in the join 4158 4159 Level: intermediate 4160 4161 Note: Currently, this is restricted to a single level join 4162 4163 Fortran Notes: 4164 Since it returns an array, this routine is only available in Fortran 90, and you must 4165 include petsc.h90 in your code. 4166 4167 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4168 4169 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4170 @*/ 4171 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4172 { 4173 DM_Plex *mesh = (DM_Plex*) dm->data; 4174 PetscInt *join[2]; 4175 PetscInt joinSize, i = 0; 4176 PetscInt dof, off, p, c, m; 4177 PetscInt maxSupportSize; 4178 4179 PetscFunctionBegin; 4180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4181 PetscValidIntPointer(points, 3); 4182 PetscValidIntPointer(numCoveredPoints, 4); 4183 PetscValidPointer(coveredPoints, 5); 4184 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4185 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4186 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4187 /* Copy in support of first point */ 4188 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4189 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4190 for (joinSize = 0; joinSize < dof; ++joinSize) { 4191 join[i][joinSize] = mesh->supports[off+joinSize]; 4192 } 4193 /* Check each successive support */ 4194 for (p = 1; p < numPoints; ++p) { 4195 PetscInt newJoinSize = 0; 4196 4197 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4198 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4199 for (c = 0; c < dof; ++c) { 4200 const PetscInt point = mesh->supports[off+c]; 4201 4202 for (m = 0; m < joinSize; ++m) { 4203 if (point == join[i][m]) { 4204 join[1-i][newJoinSize++] = point; 4205 break; 4206 } 4207 } 4208 } 4209 joinSize = newJoinSize; 4210 i = 1-i; 4211 } 4212 *numCoveredPoints = joinSize; 4213 *coveredPoints = join[i]; 4214 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4215 PetscFunctionReturn(0); 4216 } 4217 4218 /*@C 4219 DMPlexRestoreJoin - Restore an array for the join of the set of points 4220 4221 Not Collective 4222 4223 Input Parameters: 4224 + dm - The DMPlex object 4225 . numPoints - The number of input points for the join 4226 - points - The input points 4227 4228 Output Parameters: 4229 + numCoveredPoints - The number of points in the join 4230 - coveredPoints - The points in the join 4231 4232 Fortran Notes: 4233 Since it returns an array, this routine is only available in Fortran 90, and you must 4234 include petsc.h90 in your code. 4235 4236 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4237 4238 Level: intermediate 4239 4240 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4241 @*/ 4242 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4243 { 4244 PetscFunctionBegin; 4245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4246 if (points) PetscValidIntPointer(points,3); 4247 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4248 PetscValidPointer(coveredPoints, 5); 4249 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4250 if (numCoveredPoints) *numCoveredPoints = 0; 4251 PetscFunctionReturn(0); 4252 } 4253 4254 /*@C 4255 DMPlexGetFullJoin - Get an array for the join of the set of points 4256 4257 Not Collective 4258 4259 Input Parameters: 4260 + dm - The DMPlex object 4261 . numPoints - The number of input points for the join 4262 - points - The input points 4263 4264 Output Parameters: 4265 + numCoveredPoints - The number of points in the join 4266 - coveredPoints - The points in the join 4267 4268 Fortran Notes: 4269 Since it returns an array, this routine is only available in Fortran 90, and you must 4270 include petsc.h90 in your code. 4271 4272 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4273 4274 Level: intermediate 4275 4276 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4277 @*/ 4278 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4279 { 4280 PetscInt *offsets, **closures; 4281 PetscInt *join[2]; 4282 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4283 PetscInt p, d, c, m, ms; 4284 4285 PetscFunctionBegin; 4286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4287 PetscValidIntPointer(points, 3); 4288 PetscValidIntPointer(numCoveredPoints, 4); 4289 PetscValidPointer(coveredPoints, 5); 4290 4291 PetscCall(DMPlexGetDepth(dm, &depth)); 4292 PetscCall(PetscCalloc1(numPoints, &closures)); 4293 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4294 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4295 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4296 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4297 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4298 4299 for (p = 0; p < numPoints; ++p) { 4300 PetscInt closureSize; 4301 4302 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4303 4304 offsets[p*(depth+2)+0] = 0; 4305 for (d = 0; d < depth+1; ++d) { 4306 PetscInt pStart, pEnd, i; 4307 4308 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4309 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4310 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4311 offsets[p*(depth+2)+d+1] = i; 4312 break; 4313 } 4314 } 4315 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4316 } 4317 PetscCheck(offsets[p*(depth+2)+depth+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(depth+2)+depth+1], closureSize); 4318 } 4319 for (d = 0; d < depth+1; ++d) { 4320 PetscInt dof; 4321 4322 /* Copy in support of first point */ 4323 dof = offsets[d+1] - offsets[d]; 4324 for (joinSize = 0; joinSize < dof; ++joinSize) { 4325 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4326 } 4327 /* Check each successive cone */ 4328 for (p = 1; p < numPoints && joinSize; ++p) { 4329 PetscInt newJoinSize = 0; 4330 4331 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4332 for (c = 0; c < dof; ++c) { 4333 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4334 4335 for (m = 0; m < joinSize; ++m) { 4336 if (point == join[i][m]) { 4337 join[1-i][newJoinSize++] = point; 4338 break; 4339 } 4340 } 4341 } 4342 joinSize = newJoinSize; 4343 i = 1-i; 4344 } 4345 if (joinSize) break; 4346 } 4347 *numCoveredPoints = joinSize; 4348 *coveredPoints = join[i]; 4349 for (p = 0; p < numPoints; ++p) { 4350 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4351 } 4352 PetscCall(PetscFree(closures)); 4353 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4354 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4355 PetscFunctionReturn(0); 4356 } 4357 4358 /*@C 4359 DMPlexGetMeet - Get an array for the meet of the set of points 4360 4361 Not Collective 4362 4363 Input Parameters: 4364 + dm - The DMPlex object 4365 . numPoints - The number of input points for the meet 4366 - points - The input points 4367 4368 Output Parameters: 4369 + numCoveredPoints - The number of points in the meet 4370 - coveredPoints - The points in the meet 4371 4372 Level: intermediate 4373 4374 Note: Currently, this is restricted to a single level meet 4375 4376 Fortran Notes: 4377 Since it returns an array, this routine is only available in Fortran 90, and you must 4378 include petsc.h90 in your code. 4379 4380 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4381 4382 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4383 @*/ 4384 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4385 { 4386 DM_Plex *mesh = (DM_Plex*) dm->data; 4387 PetscInt *meet[2]; 4388 PetscInt meetSize, i = 0; 4389 PetscInt dof, off, p, c, m; 4390 PetscInt maxConeSize; 4391 4392 PetscFunctionBegin; 4393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4394 PetscValidIntPointer(points, 3); 4395 PetscValidIntPointer(numCoveringPoints, 4); 4396 PetscValidPointer(coveringPoints, 5); 4397 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4398 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4399 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4400 /* Copy in cone of first point */ 4401 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4402 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4403 for (meetSize = 0; meetSize < dof; ++meetSize) { 4404 meet[i][meetSize] = mesh->cones[off+meetSize]; 4405 } 4406 /* Check each successive cone */ 4407 for (p = 1; p < numPoints; ++p) { 4408 PetscInt newMeetSize = 0; 4409 4410 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4411 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4412 for (c = 0; c < dof; ++c) { 4413 const PetscInt point = mesh->cones[off+c]; 4414 4415 for (m = 0; m < meetSize; ++m) { 4416 if (point == meet[i][m]) { 4417 meet[1-i][newMeetSize++] = point; 4418 break; 4419 } 4420 } 4421 } 4422 meetSize = newMeetSize; 4423 i = 1-i; 4424 } 4425 *numCoveringPoints = meetSize; 4426 *coveringPoints = meet[i]; 4427 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4428 PetscFunctionReturn(0); 4429 } 4430 4431 /*@C 4432 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4433 4434 Not Collective 4435 4436 Input Parameters: 4437 + dm - The DMPlex object 4438 . numPoints - The number of input points for the meet 4439 - points - The input points 4440 4441 Output Parameters: 4442 + numCoveredPoints - The number of points in the meet 4443 - coveredPoints - The points in the meet 4444 4445 Level: intermediate 4446 4447 Fortran Notes: 4448 Since it returns an array, this routine is only available in Fortran 90, and you must 4449 include petsc.h90 in your code. 4450 4451 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4452 4453 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4454 @*/ 4455 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4456 { 4457 PetscFunctionBegin; 4458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4459 if (points) PetscValidIntPointer(points,3); 4460 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4461 PetscValidPointer(coveredPoints,5); 4462 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4463 if (numCoveredPoints) *numCoveredPoints = 0; 4464 PetscFunctionReturn(0); 4465 } 4466 4467 /*@C 4468 DMPlexGetFullMeet - Get an array for the meet of the set of points 4469 4470 Not Collective 4471 4472 Input Parameters: 4473 + dm - The DMPlex object 4474 . numPoints - The number of input points for the meet 4475 - points - The input points 4476 4477 Output Parameters: 4478 + numCoveredPoints - The number of points in the meet 4479 - coveredPoints - The points in the meet 4480 4481 Level: intermediate 4482 4483 Fortran Notes: 4484 Since it returns an array, this routine is only available in Fortran 90, and you must 4485 include petsc.h90 in your code. 4486 4487 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4488 4489 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4490 @*/ 4491 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4492 { 4493 PetscInt *offsets, **closures; 4494 PetscInt *meet[2]; 4495 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4496 PetscInt p, h, c, m, mc; 4497 4498 PetscFunctionBegin; 4499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4500 PetscValidIntPointer(points, 3); 4501 PetscValidIntPointer(numCoveredPoints, 4); 4502 PetscValidPointer(coveredPoints, 5); 4503 4504 PetscCall(DMPlexGetDepth(dm, &height)); 4505 PetscCall(PetscMalloc1(numPoints, &closures)); 4506 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4507 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4508 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4509 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4510 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4511 4512 for (p = 0; p < numPoints; ++p) { 4513 PetscInt closureSize; 4514 4515 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4516 4517 offsets[p*(height+2)+0] = 0; 4518 for (h = 0; h < height+1; ++h) { 4519 PetscInt pStart, pEnd, i; 4520 4521 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4522 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4523 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4524 offsets[p*(height+2)+h+1] = i; 4525 break; 4526 } 4527 } 4528 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4529 } 4530 PetscCheck(offsets[p*(height+2)+height+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(height+2)+height+1], closureSize); 4531 } 4532 for (h = 0; h < height+1; ++h) { 4533 PetscInt dof; 4534 4535 /* Copy in cone of first point */ 4536 dof = offsets[h+1] - offsets[h]; 4537 for (meetSize = 0; meetSize < dof; ++meetSize) { 4538 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4539 } 4540 /* Check each successive cone */ 4541 for (p = 1; p < numPoints && meetSize; ++p) { 4542 PetscInt newMeetSize = 0; 4543 4544 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4545 for (c = 0; c < dof; ++c) { 4546 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4547 4548 for (m = 0; m < meetSize; ++m) { 4549 if (point == meet[i][m]) { 4550 meet[1-i][newMeetSize++] = point; 4551 break; 4552 } 4553 } 4554 } 4555 meetSize = newMeetSize; 4556 i = 1-i; 4557 } 4558 if (meetSize) break; 4559 } 4560 *numCoveredPoints = meetSize; 4561 *coveredPoints = meet[i]; 4562 for (p = 0; p < numPoints; ++p) { 4563 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4564 } 4565 PetscCall(PetscFree(closures)); 4566 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4567 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4568 PetscFunctionReturn(0); 4569 } 4570 4571 /*@C 4572 DMPlexEqual - Determine if two DMs have the same topology 4573 4574 Not Collective 4575 4576 Input Parameters: 4577 + dmA - A DMPlex object 4578 - dmB - A DMPlex object 4579 4580 Output Parameters: 4581 . equal - PETSC_TRUE if the topologies are identical 4582 4583 Level: intermediate 4584 4585 Notes: 4586 We are not solving graph isomorphism, so we do not permutation. 4587 4588 .seealso: `DMPlexGetCone()` 4589 @*/ 4590 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4591 { 4592 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4593 4594 PetscFunctionBegin; 4595 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4596 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4597 PetscValidBoolPointer(equal, 3); 4598 4599 *equal = PETSC_FALSE; 4600 PetscCall(DMPlexGetDepth(dmA, &depth)); 4601 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4602 if (depth != depthB) PetscFunctionReturn(0); 4603 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4604 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4605 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4606 for (p = pStart; p < pEnd; ++p) { 4607 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4608 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4609 4610 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4611 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4612 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4613 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4614 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4615 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4616 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4617 for (c = 0; c < coneSize; ++c) { 4618 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4619 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4620 } 4621 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4622 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4623 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4624 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4625 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4626 for (s = 0; s < supportSize; ++s) { 4627 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4628 } 4629 } 4630 *equal = PETSC_TRUE; 4631 PetscFunctionReturn(0); 4632 } 4633 4634 /*@C 4635 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4636 4637 Not Collective 4638 4639 Input Parameters: 4640 + dm - The DMPlex 4641 . cellDim - The cell dimension 4642 - numCorners - The number of vertices on a cell 4643 4644 Output Parameters: 4645 . numFaceVertices - The number of vertices on a face 4646 4647 Level: developer 4648 4649 Notes: 4650 Of course this can only work for a restricted set of symmetric shapes 4651 4652 .seealso: `DMPlexGetCone()` 4653 @*/ 4654 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4655 { 4656 MPI_Comm comm; 4657 4658 PetscFunctionBegin; 4659 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4660 PetscValidIntPointer(numFaceVertices,4); 4661 switch (cellDim) { 4662 case 0: 4663 *numFaceVertices = 0; 4664 break; 4665 case 1: 4666 *numFaceVertices = 1; 4667 break; 4668 case 2: 4669 switch (numCorners) { 4670 case 3: /* triangle */ 4671 *numFaceVertices = 2; /* Edge has 2 vertices */ 4672 break; 4673 case 4: /* quadrilateral */ 4674 *numFaceVertices = 2; /* Edge has 2 vertices */ 4675 break; 4676 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4677 *numFaceVertices = 3; /* Edge has 3 vertices */ 4678 break; 4679 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4680 *numFaceVertices = 3; /* Edge has 3 vertices */ 4681 break; 4682 default: 4683 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4684 } 4685 break; 4686 case 3: 4687 switch (numCorners) { 4688 case 4: /* tetradehdron */ 4689 *numFaceVertices = 3; /* Face has 3 vertices */ 4690 break; 4691 case 6: /* tet cohesive cells */ 4692 *numFaceVertices = 4; /* Face has 4 vertices */ 4693 break; 4694 case 8: /* hexahedron */ 4695 *numFaceVertices = 4; /* Face has 4 vertices */ 4696 break; 4697 case 9: /* tet cohesive Lagrange cells */ 4698 *numFaceVertices = 6; /* Face has 6 vertices */ 4699 break; 4700 case 10: /* quadratic tetrahedron */ 4701 *numFaceVertices = 6; /* Face has 6 vertices */ 4702 break; 4703 case 12: /* hex cohesive Lagrange cells */ 4704 *numFaceVertices = 6; /* Face has 6 vertices */ 4705 break; 4706 case 18: /* quadratic tet cohesive Lagrange cells */ 4707 *numFaceVertices = 6; /* Face has 6 vertices */ 4708 break; 4709 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4710 *numFaceVertices = 9; /* Face has 9 vertices */ 4711 break; 4712 default: 4713 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4714 } 4715 break; 4716 default: 4717 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4718 } 4719 PetscFunctionReturn(0); 4720 } 4721 4722 /*@ 4723 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4724 4725 Not Collective 4726 4727 Input Parameter: 4728 . dm - The DMPlex object 4729 4730 Output Parameter: 4731 . depthLabel - The DMLabel recording point depth 4732 4733 Level: developer 4734 4735 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4736 @*/ 4737 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4738 { 4739 PetscFunctionBegin; 4740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4741 PetscValidPointer(depthLabel, 2); 4742 *depthLabel = dm->depthLabel; 4743 PetscFunctionReturn(0); 4744 } 4745 4746 /*@ 4747 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4748 4749 Not Collective 4750 4751 Input Parameter: 4752 . dm - The DMPlex object 4753 4754 Output Parameter: 4755 . depth - The number of strata (breadth first levels) in the DAG 4756 4757 Level: developer 4758 4759 Notes: 4760 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4761 The point depth is described more in detail in DMPlexGetDepthStratum(). 4762 An empty mesh gives -1. 4763 4764 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4765 @*/ 4766 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4767 { 4768 DMLabel label; 4769 PetscInt d = 0; 4770 4771 PetscFunctionBegin; 4772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4773 PetscValidIntPointer(depth, 2); 4774 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4775 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4776 *depth = d-1; 4777 PetscFunctionReturn(0); 4778 } 4779 4780 /*@ 4781 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4782 4783 Not Collective 4784 4785 Input Parameters: 4786 + dm - The DMPlex object 4787 - depth - The requested depth 4788 4789 Output Parameters: 4790 + start - The first point at this depth 4791 - end - One beyond the last point at this depth 4792 4793 Notes: 4794 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4795 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4796 higher dimension, e.g., "edges". 4797 4798 Level: developer 4799 4800 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4801 @*/ 4802 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4803 { 4804 DMLabel label; 4805 PetscInt pStart, pEnd; 4806 4807 PetscFunctionBegin; 4808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4809 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4810 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4811 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4812 if (pStart == pEnd) PetscFunctionReturn(0); 4813 if (depth < 0) { 4814 if (start) *start = pStart; 4815 if (end) *end = pEnd; 4816 PetscFunctionReturn(0); 4817 } 4818 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4819 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4820 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4821 PetscFunctionReturn(0); 4822 } 4823 4824 /*@ 4825 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4826 4827 Not Collective 4828 4829 Input Parameters: 4830 + dm - The DMPlex object 4831 - height - The requested height 4832 4833 Output Parameters: 4834 + start - The first point at this height 4835 - end - One beyond the last point at this height 4836 4837 Notes: 4838 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4839 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4840 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4841 4842 Level: developer 4843 4844 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4845 @*/ 4846 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4847 { 4848 DMLabel label; 4849 PetscInt depth, pStart, pEnd; 4850 4851 PetscFunctionBegin; 4852 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4853 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4854 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4855 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4856 if (pStart == pEnd) PetscFunctionReturn(0); 4857 if (height < 0) { 4858 if (start) *start = pStart; 4859 if (end) *end = pEnd; 4860 PetscFunctionReturn(0); 4861 } 4862 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4863 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4864 PetscCall(DMLabelGetNumValues(label, &depth)); 4865 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4866 PetscFunctionReturn(0); 4867 } 4868 4869 /*@ 4870 DMPlexGetPointDepth - Get the depth of a given point 4871 4872 Not Collective 4873 4874 Input Parameters: 4875 + dm - The DMPlex object 4876 - point - The point 4877 4878 Output Parameter: 4879 . depth - The depth of the point 4880 4881 Level: intermediate 4882 4883 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4884 @*/ 4885 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4886 { 4887 PetscFunctionBegin; 4888 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4889 PetscValidIntPointer(depth, 3); 4890 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4891 PetscFunctionReturn(0); 4892 } 4893 4894 /*@ 4895 DMPlexGetPointHeight - Get the height of a given point 4896 4897 Not Collective 4898 4899 Input Parameters: 4900 + dm - The DMPlex object 4901 - point - The point 4902 4903 Output Parameter: 4904 . height - The height of the point 4905 4906 Level: intermediate 4907 4908 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4909 @*/ 4910 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4911 { 4912 PetscInt n, pDepth; 4913 4914 PetscFunctionBegin; 4915 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4916 PetscValidIntPointer(height, 3); 4917 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4918 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4919 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4920 PetscFunctionReturn(0); 4921 } 4922 4923 /*@ 4924 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4925 4926 Not Collective 4927 4928 Input Parameter: 4929 . dm - The DMPlex object 4930 4931 Output Parameter: 4932 . celltypeLabel - The DMLabel recording cell polytope type 4933 4934 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4935 DMCreateLabel(dm, "celltype") beforehand. 4936 4937 Level: developer 4938 4939 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4940 @*/ 4941 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4942 { 4943 PetscFunctionBegin; 4944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4945 PetscValidPointer(celltypeLabel, 2); 4946 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4947 *celltypeLabel = dm->celltypeLabel; 4948 PetscFunctionReturn(0); 4949 } 4950 4951 /*@ 4952 DMPlexGetCellType - Get the polytope type of a given cell 4953 4954 Not Collective 4955 4956 Input Parameters: 4957 + dm - The DMPlex object 4958 - cell - The cell 4959 4960 Output Parameter: 4961 . celltype - The polytope type of the cell 4962 4963 Level: intermediate 4964 4965 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4966 @*/ 4967 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4968 { 4969 DMLabel label; 4970 PetscInt ct; 4971 4972 PetscFunctionBegin; 4973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4974 PetscValidPointer(celltype, 3); 4975 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4976 PetscCall(DMLabelGetValue(label, cell, &ct)); 4977 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4978 *celltype = (DMPolytopeType) ct; 4979 PetscFunctionReturn(0); 4980 } 4981 4982 /*@ 4983 DMPlexSetCellType - Set the polytope type of a given cell 4984 4985 Not Collective 4986 4987 Input Parameters: 4988 + dm - The DMPlex object 4989 . cell - The cell 4990 - celltype - The polytope type of the cell 4991 4992 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4993 is executed. This function will override the computed type. However, if automatic classification will not succeed 4994 and a user wants to manually specify all types, the classification must be disabled by calling 4995 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4996 4997 Level: advanced 4998 4999 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5000 @*/ 5001 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5002 { 5003 DMLabel label; 5004 5005 PetscFunctionBegin; 5006 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5007 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5008 PetscCall(DMLabelSetValue(label, cell, celltype)); 5009 PetscFunctionReturn(0); 5010 } 5011 5012 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5013 { 5014 PetscSection section, s; 5015 Mat m; 5016 PetscInt maxHeight; 5017 5018 PetscFunctionBegin; 5019 PetscCall(DMClone(dm, cdm)); 5020 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5021 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5022 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5023 PetscCall(DMSetLocalSection(*cdm, section)); 5024 PetscCall(PetscSectionDestroy(§ion)); 5025 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5026 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5027 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5028 PetscCall(PetscSectionDestroy(&s)); 5029 PetscCall(MatDestroy(&m)); 5030 5031 PetscCall(DMSetNumFields(*cdm, 1)); 5032 PetscCall(DMCreateDS(*cdm)); 5033 PetscFunctionReturn(0); 5034 } 5035 5036 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5037 { 5038 Vec coordsLocal, cellCoordsLocal; 5039 DM coordsDM, cellCoordsDM; 5040 5041 PetscFunctionBegin; 5042 *field = NULL; 5043 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5044 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5045 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5046 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5047 if (coordsLocal && coordsDM) { 5048 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5049 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5050 } 5051 PetscFunctionReturn(0); 5052 } 5053 5054 /*@C 5055 DMPlexGetConeSection - Return a section which describes the layout of cone data 5056 5057 Not Collective 5058 5059 Input Parameters: 5060 . dm - The DMPlex object 5061 5062 Output Parameter: 5063 . section - The PetscSection object 5064 5065 Level: developer 5066 5067 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5068 @*/ 5069 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5070 { 5071 DM_Plex *mesh = (DM_Plex*) dm->data; 5072 5073 PetscFunctionBegin; 5074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5075 if (section) *section = mesh->coneSection; 5076 PetscFunctionReturn(0); 5077 } 5078 5079 /*@C 5080 DMPlexGetSupportSection - Return a section which describes the layout of support data 5081 5082 Not Collective 5083 5084 Input Parameters: 5085 . dm - The DMPlex object 5086 5087 Output Parameter: 5088 . section - The PetscSection object 5089 5090 Level: developer 5091 5092 .seealso: `DMPlexGetConeSection()` 5093 @*/ 5094 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5095 { 5096 DM_Plex *mesh = (DM_Plex*) dm->data; 5097 5098 PetscFunctionBegin; 5099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5100 if (section) *section = mesh->supportSection; 5101 PetscFunctionReturn(0); 5102 } 5103 5104 /*@C 5105 DMPlexGetCones - Return cone data 5106 5107 Not Collective 5108 5109 Input Parameters: 5110 . dm - The DMPlex object 5111 5112 Output Parameter: 5113 . cones - The cone for each point 5114 5115 Level: developer 5116 5117 .seealso: `DMPlexGetConeSection()` 5118 @*/ 5119 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5120 { 5121 DM_Plex *mesh = (DM_Plex*) dm->data; 5122 5123 PetscFunctionBegin; 5124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5125 if (cones) *cones = mesh->cones; 5126 PetscFunctionReturn(0); 5127 } 5128 5129 /*@C 5130 DMPlexGetConeOrientations - Return cone orientation data 5131 5132 Not Collective 5133 5134 Input Parameters: 5135 . dm - The DMPlex object 5136 5137 Output Parameter: 5138 . coneOrientations - The array of cone orientations for all points 5139 5140 Level: developer 5141 5142 Notes: 5143 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5144 5145 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5146 5147 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5148 @*/ 5149 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5150 { 5151 DM_Plex *mesh = (DM_Plex*) dm->data; 5152 5153 PetscFunctionBegin; 5154 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5155 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5156 PetscFunctionReturn(0); 5157 } 5158 5159 /******************************** FEM Support **********************************/ 5160 5161 /* 5162 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5163 representing a line in the section. 5164 */ 5165 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5166 { 5167 PetscFunctionBeginHot; 5168 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5169 if (line < 0) { 5170 *k = 0; 5171 *Nc = 0; 5172 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5173 *k = 1; 5174 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5175 /* An order k SEM disc has k-1 dofs on an edge */ 5176 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5177 *k = *k / *Nc + 1; 5178 } 5179 PetscFunctionReturn(0); 5180 } 5181 5182 /*@ 5183 5184 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5185 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5186 section provided (or the section of the DM). 5187 5188 Input Parameters: 5189 + dm - The DM 5190 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5191 - section - The PetscSection to reorder, or NULL for the default section 5192 5193 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5194 degree of the basis. 5195 5196 Example: 5197 A typical interpolated single-quad mesh might order points as 5198 .vb 5199 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5200 5201 v4 -- e6 -- v3 5202 | | 5203 e7 c0 e8 5204 | | 5205 v1 -- e5 -- v2 5206 .ve 5207 5208 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5209 dofs in the order of points, e.g., 5210 .vb 5211 c0 -> [0,1,2,3] 5212 v1 -> [4] 5213 ... 5214 e5 -> [8, 9] 5215 .ve 5216 5217 which corresponds to the dofs 5218 .vb 5219 6 10 11 7 5220 13 2 3 15 5221 12 0 1 14 5222 4 8 9 5 5223 .ve 5224 5225 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5226 .vb 5227 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5228 .ve 5229 5230 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5231 .vb 5232 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5233 .ve 5234 5235 Level: developer 5236 5237 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5238 @*/ 5239 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5240 { 5241 DMLabel label; 5242 PetscInt dim, depth = -1, eStart = -1, Nf; 5243 PetscBool vertexchart; 5244 5245 PetscFunctionBegin; 5246 PetscCall(DMGetDimension(dm, &dim)); 5247 if (dim < 1) PetscFunctionReturn(0); 5248 if (point < 0) { 5249 PetscInt sStart,sEnd; 5250 5251 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5252 point = sEnd-sStart ? sStart : point; 5253 } 5254 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5255 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5256 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5257 if (depth == 1) {eStart = point;} 5258 else if (depth == dim) { 5259 const PetscInt *cone; 5260 5261 PetscCall(DMPlexGetCone(dm, point, &cone)); 5262 if (dim == 2) eStart = cone[0]; 5263 else if (dim == 3) { 5264 const PetscInt *cone2; 5265 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5266 eStart = cone2[0]; 5267 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5268 } else PetscCheck(depth < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5269 { /* Determine whether the chart covers all points or just vertices. */ 5270 PetscInt pStart,pEnd,cStart,cEnd; 5271 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5272 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5273 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5274 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5275 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5276 } 5277 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5278 for (PetscInt d=1; d<=dim; d++) { 5279 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5280 PetscInt *perm; 5281 5282 for (f = 0; f < Nf; ++f) { 5283 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5284 size += PetscPowInt(k+1, d)*Nc; 5285 } 5286 PetscCall(PetscMalloc1(size, &perm)); 5287 for (f = 0; f < Nf; ++f) { 5288 switch (d) { 5289 case 1: 5290 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5291 /* 5292 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5293 We want [ vtx0; edge of length k-1; vtx1 ] 5294 */ 5295 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5296 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5297 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5298 foffset = offset; 5299 break; 5300 case 2: 5301 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5302 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5303 /* The SEM order is 5304 5305 v_lb, {e_b}, v_rb, 5306 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5307 v_lt, reverse {e_t}, v_rt 5308 */ 5309 { 5310 const PetscInt of = 0; 5311 const PetscInt oeb = of + PetscSqr(k-1); 5312 const PetscInt oer = oeb + (k-1); 5313 const PetscInt oet = oer + (k-1); 5314 const PetscInt oel = oet + (k-1); 5315 const PetscInt ovlb = oel + (k-1); 5316 const PetscInt ovrb = ovlb + 1; 5317 const PetscInt ovrt = ovrb + 1; 5318 const PetscInt ovlt = ovrt + 1; 5319 PetscInt o; 5320 5321 /* bottom */ 5322 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5323 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5324 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5325 /* middle */ 5326 for (i = 0; i < k-1; ++i) { 5327 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5328 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; 5329 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5330 } 5331 /* top */ 5332 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5333 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5334 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5335 foffset = offset; 5336 } 5337 break; 5338 case 3: 5339 /* The original hex closure is 5340 5341 {c, 5342 f_b, f_t, f_f, f_b, f_r, f_l, 5343 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5344 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5345 */ 5346 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5347 /* The SEM order is 5348 Bottom Slice 5349 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5350 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5351 v_blb, {e_bb}, v_brb, 5352 5353 Middle Slice (j) 5354 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5355 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5356 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5357 5358 Top Slice 5359 v_tlf, {e_tf}, v_trf, 5360 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5361 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5362 */ 5363 { 5364 const PetscInt oc = 0; 5365 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5366 const PetscInt oft = ofb + PetscSqr(k-1); 5367 const PetscInt off = oft + PetscSqr(k-1); 5368 const PetscInt ofk = off + PetscSqr(k-1); 5369 const PetscInt ofr = ofk + PetscSqr(k-1); 5370 const PetscInt ofl = ofr + PetscSqr(k-1); 5371 const PetscInt oebl = ofl + PetscSqr(k-1); 5372 const PetscInt oebb = oebl + (k-1); 5373 const PetscInt oebr = oebb + (k-1); 5374 const PetscInt oebf = oebr + (k-1); 5375 const PetscInt oetf = oebf + (k-1); 5376 const PetscInt oetr = oetf + (k-1); 5377 const PetscInt oetb = oetr + (k-1); 5378 const PetscInt oetl = oetb + (k-1); 5379 const PetscInt oerf = oetl + (k-1); 5380 const PetscInt oelf = oerf + (k-1); 5381 const PetscInt oelb = oelf + (k-1); 5382 const PetscInt oerb = oelb + (k-1); 5383 const PetscInt ovblf = oerb + (k-1); 5384 const PetscInt ovblb = ovblf + 1; 5385 const PetscInt ovbrb = ovblb + 1; 5386 const PetscInt ovbrf = ovbrb + 1; 5387 const PetscInt ovtlf = ovbrf + 1; 5388 const PetscInt ovtrf = ovtlf + 1; 5389 const PetscInt ovtrb = ovtrf + 1; 5390 const PetscInt ovtlb = ovtrb + 1; 5391 PetscInt o, n; 5392 5393 /* Bottom Slice */ 5394 /* bottom */ 5395 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5396 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5397 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5398 /* middle */ 5399 for (i = 0; i < k-1; ++i) { 5400 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5401 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;} 5402 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5403 } 5404 /* top */ 5405 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5406 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5407 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5408 5409 /* Middle Slice */ 5410 for (j = 0; j < k-1; ++j) { 5411 /* bottom */ 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5413 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; 5414 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5415 /* middle */ 5416 for (i = 0; i < k-1; ++i) { 5417 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5418 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; 5419 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5420 } 5421 /* top */ 5422 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5423 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; 5424 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5425 } 5426 5427 /* Top Slice */ 5428 /* bottom */ 5429 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5430 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5431 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5432 /* middle */ 5433 for (i = 0; i < k-1; ++i) { 5434 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5435 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5436 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5437 } 5438 /* top */ 5439 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5440 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5441 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5442 5443 foffset = offset; 5444 } 5445 break; 5446 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5447 } 5448 } 5449 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5450 /* Check permutation */ 5451 { 5452 PetscInt *check; 5453 5454 PetscCall(PetscMalloc1(size, &check)); 5455 for (i = 0; i < size; ++i) { 5456 check[i] = -1; 5457 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5458 } 5459 for (i = 0; i < size; ++i) check[perm[i]] = i; 5460 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5461 PetscCall(PetscFree(check)); 5462 } 5463 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5464 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5465 PetscInt *loc_perm; 5466 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5467 for (PetscInt i=0; i<size; i++) { 5468 loc_perm[i] = perm[i]; 5469 loc_perm[size+i] = size + perm[i]; 5470 } 5471 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5472 } 5473 } 5474 PetscFunctionReturn(0); 5475 } 5476 5477 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5478 { 5479 PetscDS prob; 5480 PetscInt depth, Nf, h; 5481 DMLabel label; 5482 5483 PetscFunctionBeginHot; 5484 PetscCall(DMGetDS(dm, &prob)); 5485 Nf = prob->Nf; 5486 label = dm->depthLabel; 5487 *dspace = NULL; 5488 if (field < Nf) { 5489 PetscObject disc = prob->disc[field]; 5490 5491 if (disc->classid == PETSCFE_CLASSID) { 5492 PetscDualSpace dsp; 5493 5494 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5495 PetscCall(DMLabelGetNumValues(label,&depth)); 5496 PetscCall(DMLabelGetValue(label,point,&h)); 5497 h = depth - 1 - h; 5498 if (h) { 5499 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5500 } else { 5501 *dspace = dsp; 5502 } 5503 } 5504 } 5505 PetscFunctionReturn(0); 5506 } 5507 5508 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5509 { 5510 PetscScalar *array; 5511 const PetscScalar *vArray; 5512 const PetscInt *cone, *coneO; 5513 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5514 5515 PetscFunctionBeginHot; 5516 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5517 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5518 PetscCall(DMPlexGetCone(dm, point, &cone)); 5519 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5520 if (!values || !*values) { 5521 if ((point >= pStart) && (point < pEnd)) { 5522 PetscInt dof; 5523 5524 PetscCall(PetscSectionGetDof(section, point, &dof)); 5525 size += dof; 5526 } 5527 for (p = 0; p < numPoints; ++p) { 5528 const PetscInt cp = cone[p]; 5529 PetscInt dof; 5530 5531 if ((cp < pStart) || (cp >= pEnd)) continue; 5532 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5533 size += dof; 5534 } 5535 if (!values) { 5536 if (csize) *csize = size; 5537 PetscFunctionReturn(0); 5538 } 5539 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5540 } else { 5541 array = *values; 5542 } 5543 size = 0; 5544 PetscCall(VecGetArrayRead(v, &vArray)); 5545 if ((point >= pStart) && (point < pEnd)) { 5546 PetscInt dof, off, d; 5547 const PetscScalar *varr; 5548 5549 PetscCall(PetscSectionGetDof(section, point, &dof)); 5550 PetscCall(PetscSectionGetOffset(section, point, &off)); 5551 varr = &vArray[off]; 5552 for (d = 0; d < dof; ++d, ++offset) { 5553 array[offset] = varr[d]; 5554 } 5555 size += dof; 5556 } 5557 for (p = 0; p < numPoints; ++p) { 5558 const PetscInt cp = cone[p]; 5559 PetscInt o = coneO[p]; 5560 PetscInt dof, off, d; 5561 const PetscScalar *varr; 5562 5563 if ((cp < pStart) || (cp >= pEnd)) continue; 5564 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5565 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5566 varr = &vArray[off]; 5567 if (o >= 0) { 5568 for (d = 0; d < dof; ++d, ++offset) { 5569 array[offset] = varr[d]; 5570 } 5571 } else { 5572 for (d = dof-1; d >= 0; --d, ++offset) { 5573 array[offset] = varr[d]; 5574 } 5575 } 5576 size += dof; 5577 } 5578 PetscCall(VecRestoreArrayRead(v, &vArray)); 5579 if (!*values) { 5580 if (csize) *csize = size; 5581 *values = array; 5582 } else { 5583 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5584 *csize = size; 5585 } 5586 PetscFunctionReturn(0); 5587 } 5588 5589 /* Compress out points not in the section */ 5590 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5591 { 5592 const PetscInt np = *numPoints; 5593 PetscInt pStart, pEnd, p, q; 5594 5595 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5596 for (p = 0, q = 0; p < np; ++p) { 5597 const PetscInt r = points[p*2]; 5598 if ((r >= pStart) && (r < pEnd)) { 5599 points[q*2] = r; 5600 points[q*2+1] = points[p*2+1]; 5601 ++q; 5602 } 5603 } 5604 *numPoints = q; 5605 return 0; 5606 } 5607 5608 /* Compressed closure does not apply closure permutation */ 5609 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5610 { 5611 const PetscInt *cla = NULL; 5612 PetscInt np, *pts = NULL; 5613 5614 PetscFunctionBeginHot; 5615 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5616 if (*clPoints) { 5617 PetscInt dof, off; 5618 5619 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5620 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5621 PetscCall(ISGetIndices(*clPoints, &cla)); 5622 np = dof/2; 5623 pts = (PetscInt *) &cla[off]; 5624 } else { 5625 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5626 PetscCall(CompressPoints_Private(section, &np, pts)); 5627 } 5628 *numPoints = np; 5629 *points = pts; 5630 *clp = cla; 5631 PetscFunctionReturn(0); 5632 } 5633 5634 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5635 { 5636 PetscFunctionBeginHot; 5637 if (!*clPoints) { 5638 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5639 } else { 5640 PetscCall(ISRestoreIndices(*clPoints, clp)); 5641 } 5642 *numPoints = 0; 5643 *points = NULL; 5644 *clSec = NULL; 5645 *clPoints = NULL; 5646 *clp = NULL; 5647 PetscFunctionReturn(0); 5648 } 5649 5650 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5651 { 5652 PetscInt offset = 0, p; 5653 const PetscInt **perms = NULL; 5654 const PetscScalar **flips = NULL; 5655 5656 PetscFunctionBeginHot; 5657 *size = 0; 5658 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5659 for (p = 0; p < numPoints; p++) { 5660 const PetscInt point = points[2*p]; 5661 const PetscInt *perm = perms ? perms[p] : NULL; 5662 const PetscScalar *flip = flips ? flips[p] : NULL; 5663 PetscInt dof, off, d; 5664 const PetscScalar *varr; 5665 5666 PetscCall(PetscSectionGetDof(section, point, &dof)); 5667 PetscCall(PetscSectionGetOffset(section, point, &off)); 5668 varr = &vArray[off]; 5669 if (clperm) { 5670 if (perm) { 5671 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5672 } else { 5673 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5674 } 5675 if (flip) { 5676 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5677 } 5678 } else { 5679 if (perm) { 5680 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5681 } else { 5682 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5683 } 5684 if (flip) { 5685 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5686 } 5687 } 5688 offset += dof; 5689 } 5690 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5691 *size = offset; 5692 PetscFunctionReturn(0); 5693 } 5694 5695 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[]) 5696 { 5697 PetscInt offset = 0, f; 5698 5699 PetscFunctionBeginHot; 5700 *size = 0; 5701 for (f = 0; f < numFields; ++f) { 5702 PetscInt p; 5703 const PetscInt **perms = NULL; 5704 const PetscScalar **flips = NULL; 5705 5706 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5707 for (p = 0; p < numPoints; p++) { 5708 const PetscInt point = points[2*p]; 5709 PetscInt fdof, foff, b; 5710 const PetscScalar *varr; 5711 const PetscInt *perm = perms ? perms[p] : NULL; 5712 const PetscScalar *flip = flips ? flips[p] : NULL; 5713 5714 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5715 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5716 varr = &vArray[foff]; 5717 if (clperm) { 5718 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5719 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5720 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5721 } else { 5722 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5723 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5724 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5725 } 5726 offset += fdof; 5727 } 5728 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5729 } 5730 *size = offset; 5731 PetscFunctionReturn(0); 5732 } 5733 5734 /*@C 5735 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5736 5737 Not collective 5738 5739 Input Parameters: 5740 + dm - The DM 5741 . section - The section describing the layout in v, or NULL to use the default section 5742 . v - The local vector 5743 - point - The point in the DM 5744 5745 Input/Output Parameters: 5746 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5747 - values - An array to use for the values, or NULL to have it allocated automatically; 5748 if the user provided NULL, it is a borrowed array and should not be freed 5749 5750 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5751 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5752 $ assembly function, and a user may already have allocated storage for this operation. 5753 $ 5754 $ A typical use could be 5755 $ 5756 $ values = NULL; 5757 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5758 $ for (cl = 0; cl < clSize; ++cl) { 5759 $ <Compute on closure> 5760 $ } 5761 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5762 $ 5763 $ or 5764 $ 5765 $ PetscMalloc1(clMaxSize, &values); 5766 $ for (p = pStart; p < pEnd; ++p) { 5767 $ clSize = clMaxSize; 5768 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5769 $ for (cl = 0; cl < clSize; ++cl) { 5770 $ <Compute on closure> 5771 $ } 5772 $ } 5773 $ PetscFree(values); 5774 5775 Fortran Notes: 5776 Since it returns an array, this routine is only available in Fortran 90, and you must 5777 include petsc.h90 in your code. 5778 5779 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5780 5781 Level: intermediate 5782 5783 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5784 @*/ 5785 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5786 { 5787 PetscSection clSection; 5788 IS clPoints; 5789 PetscInt *points = NULL; 5790 const PetscInt *clp, *perm; 5791 PetscInt depth, numFields, numPoints, asize; 5792 5793 PetscFunctionBeginHot; 5794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5795 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5796 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5797 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5798 PetscCall(DMPlexGetDepth(dm, &depth)); 5799 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5800 if (depth == 1 && numFields < 2) { 5801 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5802 PetscFunctionReturn(0); 5803 } 5804 /* Get points */ 5805 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5806 /* Get sizes */ 5807 asize = 0; 5808 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5809 PetscInt dof; 5810 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5811 asize += dof; 5812 } 5813 if (values) { 5814 const PetscScalar *vArray; 5815 PetscInt size; 5816 5817 if (*values) { 5818 PetscCheck(*csize >= asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 5819 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5820 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5821 PetscCall(VecGetArrayRead(v, &vArray)); 5822 /* Get values */ 5823 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5824 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5825 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5826 /* Cleanup array */ 5827 PetscCall(VecRestoreArrayRead(v, &vArray)); 5828 } 5829 if (csize) *csize = asize; 5830 /* Cleanup points */ 5831 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5832 PetscFunctionReturn(0); 5833 } 5834 5835 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5836 { 5837 DMLabel depthLabel; 5838 PetscSection clSection; 5839 IS clPoints; 5840 PetscScalar *array; 5841 const PetscScalar *vArray; 5842 PetscInt *points = NULL; 5843 const PetscInt *clp, *perm = NULL; 5844 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5845 5846 PetscFunctionBeginHot; 5847 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5848 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5849 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5850 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5851 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5852 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5853 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5854 if (mdepth == 1 && numFields < 2) { 5855 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5856 PetscFunctionReturn(0); 5857 } 5858 /* Get points */ 5859 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5860 for (clsize=0,p=0; p<Np; p++) { 5861 PetscInt dof; 5862 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5863 clsize += dof; 5864 } 5865 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5866 /* Filter points */ 5867 for (p = 0; p < numPoints*2; p += 2) { 5868 PetscInt dep; 5869 5870 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5871 if (dep != depth) continue; 5872 points[Np*2+0] = points[p]; 5873 points[Np*2+1] = points[p+1]; 5874 ++Np; 5875 } 5876 /* Get array */ 5877 if (!values || !*values) { 5878 PetscInt asize = 0, dof; 5879 5880 for (p = 0; p < Np*2; p += 2) { 5881 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5882 asize += dof; 5883 } 5884 if (!values) { 5885 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5886 if (csize) *csize = asize; 5887 PetscFunctionReturn(0); 5888 } 5889 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5890 } else { 5891 array = *values; 5892 } 5893 PetscCall(VecGetArrayRead(v, &vArray)); 5894 /* Get values */ 5895 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5896 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5897 /* Cleanup points */ 5898 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5899 /* Cleanup array */ 5900 PetscCall(VecRestoreArrayRead(v, &vArray)); 5901 if (!*values) { 5902 if (csize) *csize = size; 5903 *values = array; 5904 } else { 5905 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5906 *csize = size; 5907 } 5908 PetscFunctionReturn(0); 5909 } 5910 5911 /*@C 5912 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5913 5914 Not collective 5915 5916 Input Parameters: 5917 + dm - The DM 5918 . section - The section describing the layout in v, or NULL to use the default section 5919 . v - The local vector 5920 . point - The point in the DM 5921 . csize - The number of values in the closure, or NULL 5922 - values - The array of values, which is a borrowed array and should not be freed 5923 5924 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5925 5926 Fortran Notes: 5927 Since it returns an array, this routine is only available in Fortran 90, and you must 5928 include petsc.h90 in your code. 5929 5930 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5931 5932 Level: intermediate 5933 5934 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5935 @*/ 5936 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5937 { 5938 PetscInt size = 0; 5939 5940 PetscFunctionBegin; 5941 /* Should work without recalculating size */ 5942 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5943 *values = NULL; 5944 PetscFunctionReturn(0); 5945 } 5946 5947 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5948 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5949 5950 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[]) 5951 { 5952 PetscInt cdof; /* The number of constraints on this point */ 5953 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5954 PetscScalar *a; 5955 PetscInt off, cind = 0, k; 5956 5957 PetscFunctionBegin; 5958 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5959 PetscCall(PetscSectionGetOffset(section, point, &off)); 5960 a = &array[off]; 5961 if (!cdof || setBC) { 5962 if (clperm) { 5963 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5964 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5965 } else { 5966 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5967 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5968 } 5969 } else { 5970 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5971 if (clperm) { 5972 if (perm) {for (k = 0; k < dof; ++k) { 5973 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5974 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5975 } 5976 } else { 5977 for (k = 0; k < dof; ++k) { 5978 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5979 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5980 } 5981 } 5982 } else { 5983 if (perm) { 5984 for (k = 0; k < dof; ++k) { 5985 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5986 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5987 } 5988 } else { 5989 for (k = 0; k < dof; ++k) { 5990 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5991 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5992 } 5993 } 5994 } 5995 } 5996 PetscFunctionReturn(0); 5997 } 5998 5999 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[]) 6000 { 6001 PetscInt cdof; /* The number of constraints on this point */ 6002 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6003 PetscScalar *a; 6004 PetscInt off, cind = 0, k; 6005 6006 PetscFunctionBegin; 6007 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6008 PetscCall(PetscSectionGetOffset(section, point, &off)); 6009 a = &array[off]; 6010 if (cdof) { 6011 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6012 if (clperm) { 6013 if (perm) { 6014 for (k = 0; k < dof; ++k) { 6015 if ((cind < cdof) && (k == cdofs[cind])) { 6016 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6017 cind++; 6018 } 6019 } 6020 } else { 6021 for (k = 0; k < dof; ++k) { 6022 if ((cind < cdof) && (k == cdofs[cind])) { 6023 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6024 cind++; 6025 } 6026 } 6027 } 6028 } else { 6029 if (perm) { 6030 for (k = 0; k < dof; ++k) { 6031 if ((cind < cdof) && (k == cdofs[cind])) { 6032 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6033 cind++; 6034 } 6035 } 6036 } else { 6037 for (k = 0; k < dof; ++k) { 6038 if ((cind < cdof) && (k == cdofs[cind])) { 6039 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6040 cind++; 6041 } 6042 } 6043 } 6044 } 6045 } 6046 PetscFunctionReturn(0); 6047 } 6048 6049 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[]) 6050 { 6051 PetscScalar *a; 6052 PetscInt fdof, foff, fcdof, foffset = *offset; 6053 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6054 PetscInt cind = 0, b; 6055 6056 PetscFunctionBegin; 6057 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6058 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6059 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6060 a = &array[foff]; 6061 if (!fcdof || setBC) { 6062 if (clperm) { 6063 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6064 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6065 } else { 6066 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6067 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6068 } 6069 } else { 6070 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6071 if (clperm) { 6072 if (perm) { 6073 for (b = 0; b < fdof; b++) { 6074 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6075 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6076 } 6077 } else { 6078 for (b = 0; b < fdof; b++) { 6079 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6080 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6081 } 6082 } 6083 } else { 6084 if (perm) { 6085 for (b = 0; b < fdof; b++) { 6086 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6087 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6088 } 6089 } else { 6090 for (b = 0; b < fdof; b++) { 6091 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6092 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6093 } 6094 } 6095 } 6096 } 6097 *offset += fdof; 6098 PetscFunctionReturn(0); 6099 } 6100 6101 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[]) 6102 { 6103 PetscScalar *a; 6104 PetscInt fdof, foff, fcdof, foffset = *offset; 6105 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6106 PetscInt Nc, cind = 0, ncind = 0, b; 6107 PetscBool ncSet, fcSet; 6108 6109 PetscFunctionBegin; 6110 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6111 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6112 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6113 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6114 a = &array[foff]; 6115 if (fcdof) { 6116 /* We just override fcdof and fcdofs with Ncc and comps */ 6117 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6118 if (clperm) { 6119 if (perm) { 6120 if (comps) { 6121 for (b = 0; b < fdof; b++) { 6122 ncSet = fcSet = PETSC_FALSE; 6123 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6124 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6125 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6126 } 6127 } else { 6128 for (b = 0; b < fdof; b++) { 6129 if ((cind < fcdof) && (b == fcdofs[cind])) { 6130 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6131 ++cind; 6132 } 6133 } 6134 } 6135 } else { 6136 if (comps) { 6137 for (b = 0; b < fdof; b++) { 6138 ncSet = fcSet = PETSC_FALSE; 6139 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6140 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6141 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6142 } 6143 } else { 6144 for (b = 0; b < fdof; b++) { 6145 if ((cind < fcdof) && (b == fcdofs[cind])) { 6146 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6147 ++cind; 6148 } 6149 } 6150 } 6151 } 6152 } else { 6153 if (perm) { 6154 if (comps) { 6155 for (b = 0; b < fdof; b++) { 6156 ncSet = fcSet = PETSC_FALSE; 6157 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6158 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6159 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6160 } 6161 } else { 6162 for (b = 0; b < fdof; b++) { 6163 if ((cind < fcdof) && (b == fcdofs[cind])) { 6164 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6165 ++cind; 6166 } 6167 } 6168 } 6169 } else { 6170 if (comps) { 6171 for (b = 0; b < fdof; b++) { 6172 ncSet = fcSet = PETSC_FALSE; 6173 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6174 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6175 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6176 } 6177 } else { 6178 for (b = 0; b < fdof; b++) { 6179 if ((cind < fcdof) && (b == fcdofs[cind])) { 6180 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6181 ++cind; 6182 } 6183 } 6184 } 6185 } 6186 } 6187 } 6188 *offset += fdof; 6189 PetscFunctionReturn(0); 6190 } 6191 6192 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6193 { 6194 PetscScalar *array; 6195 const PetscInt *cone, *coneO; 6196 PetscInt pStart, pEnd, p, numPoints, off, dof; 6197 6198 PetscFunctionBeginHot; 6199 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6200 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6201 PetscCall(DMPlexGetCone(dm, point, &cone)); 6202 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6203 PetscCall(VecGetArray(v, &array)); 6204 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6205 const PetscInt cp = !p ? point : cone[p-1]; 6206 const PetscInt o = !p ? 0 : coneO[p-1]; 6207 6208 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6209 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6210 /* ADD_VALUES */ 6211 { 6212 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6213 PetscScalar *a; 6214 PetscInt cdof, coff, cind = 0, k; 6215 6216 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6217 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6218 a = &array[coff]; 6219 if (!cdof) { 6220 if (o >= 0) { 6221 for (k = 0; k < dof; ++k) { 6222 a[k] += values[off+k]; 6223 } 6224 } else { 6225 for (k = 0; k < dof; ++k) { 6226 a[k] += values[off+dof-k-1]; 6227 } 6228 } 6229 } else { 6230 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6231 if (o >= 0) { 6232 for (k = 0; k < dof; ++k) { 6233 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6234 a[k] += values[off+k]; 6235 } 6236 } else { 6237 for (k = 0; k < dof; ++k) { 6238 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6239 a[k] += values[off+dof-k-1]; 6240 } 6241 } 6242 } 6243 } 6244 } 6245 PetscCall(VecRestoreArray(v, &array)); 6246 PetscFunctionReturn(0); 6247 } 6248 6249 /*@C 6250 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6251 6252 Not collective 6253 6254 Input Parameters: 6255 + dm - The DM 6256 . section - The section describing the layout in v, or NULL to use the default section 6257 . v - The local vector 6258 . point - The point in the DM 6259 . values - The array of values 6260 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6261 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6262 6263 Fortran Notes: 6264 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6265 6266 Level: intermediate 6267 6268 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6269 @*/ 6270 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6271 { 6272 PetscSection clSection; 6273 IS clPoints; 6274 PetscScalar *array; 6275 PetscInt *points = NULL; 6276 const PetscInt *clp, *clperm = NULL; 6277 PetscInt depth, numFields, numPoints, p, clsize; 6278 6279 PetscFunctionBeginHot; 6280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6281 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6282 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6283 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6284 PetscCall(DMPlexGetDepth(dm, &depth)); 6285 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6286 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6287 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6288 PetscFunctionReturn(0); 6289 } 6290 /* Get points */ 6291 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6292 for (clsize=0,p=0; p<numPoints; p++) { 6293 PetscInt dof; 6294 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6295 clsize += dof; 6296 } 6297 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6298 /* Get array */ 6299 PetscCall(VecGetArray(v, &array)); 6300 /* Get values */ 6301 if (numFields > 0) { 6302 PetscInt offset = 0, f; 6303 for (f = 0; f < numFields; ++f) { 6304 const PetscInt **perms = NULL; 6305 const PetscScalar **flips = NULL; 6306 6307 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6308 switch (mode) { 6309 case INSERT_VALUES: 6310 for (p = 0; p < numPoints; p++) { 6311 const PetscInt point = points[2*p]; 6312 const PetscInt *perm = perms ? perms[p] : NULL; 6313 const PetscScalar *flip = flips ? flips[p] : NULL; 6314 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6315 } break; 6316 case INSERT_ALL_VALUES: 6317 for (p = 0; p < numPoints; p++) { 6318 const PetscInt point = points[2*p]; 6319 const PetscInt *perm = perms ? perms[p] : NULL; 6320 const PetscScalar *flip = flips ? flips[p] : NULL; 6321 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6322 } break; 6323 case INSERT_BC_VALUES: 6324 for (p = 0; p < numPoints; p++) { 6325 const PetscInt point = points[2*p]; 6326 const PetscInt *perm = perms ? perms[p] : NULL; 6327 const PetscScalar *flip = flips ? flips[p] : NULL; 6328 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6329 } break; 6330 case ADD_VALUES: 6331 for (p = 0; p < numPoints; p++) { 6332 const PetscInt point = points[2*p]; 6333 const PetscInt *perm = perms ? perms[p] : NULL; 6334 const PetscScalar *flip = flips ? flips[p] : NULL; 6335 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6336 } break; 6337 case ADD_ALL_VALUES: 6338 for (p = 0; p < numPoints; p++) { 6339 const PetscInt point = points[2*p]; 6340 const PetscInt *perm = perms ? perms[p] : NULL; 6341 const PetscScalar *flip = flips ? flips[p] : NULL; 6342 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6343 } break; 6344 case ADD_BC_VALUES: 6345 for (p = 0; p < numPoints; p++) { 6346 const PetscInt point = points[2*p]; 6347 const PetscInt *perm = perms ? perms[p] : NULL; 6348 const PetscScalar *flip = flips ? flips[p] : NULL; 6349 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6350 } break; 6351 default: 6352 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6353 } 6354 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6355 } 6356 } else { 6357 PetscInt dof, off; 6358 const PetscInt **perms = NULL; 6359 const PetscScalar **flips = NULL; 6360 6361 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6362 switch (mode) { 6363 case INSERT_VALUES: 6364 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6365 const PetscInt point = points[2*p]; 6366 const PetscInt *perm = perms ? perms[p] : NULL; 6367 const PetscScalar *flip = flips ? flips[p] : NULL; 6368 PetscCall(PetscSectionGetDof(section, point, &dof)); 6369 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6370 } break; 6371 case INSERT_ALL_VALUES: 6372 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6373 const PetscInt point = points[2*p]; 6374 const PetscInt *perm = perms ? perms[p] : NULL; 6375 const PetscScalar *flip = flips ? flips[p] : NULL; 6376 PetscCall(PetscSectionGetDof(section, point, &dof)); 6377 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6378 } break; 6379 case INSERT_BC_VALUES: 6380 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6381 const PetscInt point = points[2*p]; 6382 const PetscInt *perm = perms ? perms[p] : NULL; 6383 const PetscScalar *flip = flips ? flips[p] : NULL; 6384 PetscCall(PetscSectionGetDof(section, point, &dof)); 6385 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6386 } break; 6387 case ADD_VALUES: 6388 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6389 const PetscInt point = points[2*p]; 6390 const PetscInt *perm = perms ? perms[p] : NULL; 6391 const PetscScalar *flip = flips ? flips[p] : NULL; 6392 PetscCall(PetscSectionGetDof(section, point, &dof)); 6393 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6394 } break; 6395 case ADD_ALL_VALUES: 6396 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6397 const PetscInt point = points[2*p]; 6398 const PetscInt *perm = perms ? perms[p] : NULL; 6399 const PetscScalar *flip = flips ? flips[p] : NULL; 6400 PetscCall(PetscSectionGetDof(section, point, &dof)); 6401 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6402 } break; 6403 case ADD_BC_VALUES: 6404 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6405 const PetscInt point = points[2*p]; 6406 const PetscInt *perm = perms ? perms[p] : NULL; 6407 const PetscScalar *flip = flips ? flips[p] : NULL; 6408 PetscCall(PetscSectionGetDof(section, point, &dof)); 6409 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6410 } break; 6411 default: 6412 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6413 } 6414 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6415 } 6416 /* Cleanup points */ 6417 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6418 /* Cleanup array */ 6419 PetscCall(VecRestoreArray(v, &array)); 6420 PetscFunctionReturn(0); 6421 } 6422 6423 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6424 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6425 { 6426 PetscFunctionBegin; 6427 if (label) { 6428 PetscBool contains; 6429 PetscInt fdof; 6430 6431 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6432 if (!contains) { 6433 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6434 *offset += fdof; 6435 PetscFunctionReturn(1); 6436 } 6437 } 6438 PetscFunctionReturn(0); 6439 } 6440 6441 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6442 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) 6443 { 6444 PetscSection clSection; 6445 IS clPoints; 6446 PetscScalar *array; 6447 PetscInt *points = NULL; 6448 const PetscInt *clp; 6449 PetscInt numFields, numPoints, p; 6450 PetscInt offset = 0, f; 6451 6452 PetscFunctionBeginHot; 6453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6454 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6455 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6456 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6457 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6458 /* Get points */ 6459 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6460 /* Get array */ 6461 PetscCall(VecGetArray(v, &array)); 6462 /* Get values */ 6463 for (f = 0; f < numFields; ++f) { 6464 const PetscInt **perms = NULL; 6465 const PetscScalar **flips = NULL; 6466 6467 if (!fieldActive[f]) { 6468 for (p = 0; p < numPoints*2; p += 2) { 6469 PetscInt fdof; 6470 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6471 offset += fdof; 6472 } 6473 continue; 6474 } 6475 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6476 switch (mode) { 6477 case INSERT_VALUES: 6478 for (p = 0; p < numPoints; p++) { 6479 const PetscInt point = points[2*p]; 6480 const PetscInt *perm = perms ? perms[p] : NULL; 6481 const PetscScalar *flip = flips ? flips[p] : NULL; 6482 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6483 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6484 } break; 6485 case INSERT_ALL_VALUES: 6486 for (p = 0; p < numPoints; p++) { 6487 const PetscInt point = points[2*p]; 6488 const PetscInt *perm = perms ? perms[p] : NULL; 6489 const PetscScalar *flip = flips ? flips[p] : NULL; 6490 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6491 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6492 } break; 6493 case INSERT_BC_VALUES: 6494 for (p = 0; p < numPoints; p++) { 6495 const PetscInt point = points[2*p]; 6496 const PetscInt *perm = perms ? perms[p] : NULL; 6497 const PetscScalar *flip = flips ? flips[p] : NULL; 6498 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6499 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6500 } break; 6501 case ADD_VALUES: 6502 for (p = 0; p < numPoints; p++) { 6503 const PetscInt point = points[2*p]; 6504 const PetscInt *perm = perms ? perms[p] : NULL; 6505 const PetscScalar *flip = flips ? flips[p] : NULL; 6506 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6507 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6508 } break; 6509 case ADD_ALL_VALUES: 6510 for (p = 0; p < numPoints; p++) { 6511 const PetscInt point = points[2*p]; 6512 const PetscInt *perm = perms ? perms[p] : NULL; 6513 const PetscScalar *flip = flips ? flips[p] : NULL; 6514 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6515 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6516 } break; 6517 default: 6518 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6519 } 6520 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6521 } 6522 /* Cleanup points */ 6523 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6524 /* Cleanup array */ 6525 PetscCall(VecRestoreArray(v, &array)); 6526 PetscFunctionReturn(0); 6527 } 6528 6529 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6530 { 6531 PetscMPIInt rank; 6532 PetscInt i, j; 6533 6534 PetscFunctionBegin; 6535 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6536 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6537 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6538 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6539 numCIndices = numCIndices ? numCIndices : numRIndices; 6540 if (!values) PetscFunctionReturn(0); 6541 for (i = 0; i < numRIndices; i++) { 6542 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6543 for (j = 0; j < numCIndices; j++) { 6544 #if defined(PETSC_USE_COMPLEX) 6545 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6546 #else 6547 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6548 #endif 6549 } 6550 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6551 } 6552 PetscFunctionReturn(0); 6553 } 6554 6555 /* 6556 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6557 6558 Input Parameters: 6559 + section - The section for this data layout 6560 . islocal - Is the section (and thus indices being requested) local or global? 6561 . point - The point contributing dofs with these indices 6562 . off - The global offset of this point 6563 . loff - The local offset of each field 6564 . setBC - The flag determining whether to include indices of boundary values 6565 . perm - A permutation of the dofs on this point, or NULL 6566 - indperm - A permutation of the entire indices array, or NULL 6567 6568 Output Parameter: 6569 . indices - Indices for dofs on this point 6570 6571 Level: developer 6572 6573 Note: The indices could be local or global, depending on the value of 'off'. 6574 */ 6575 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6576 { 6577 PetscInt dof; /* The number of unknowns on this point */ 6578 PetscInt cdof; /* The number of constraints on this point */ 6579 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6580 PetscInt cind = 0, k; 6581 6582 PetscFunctionBegin; 6583 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6584 PetscCall(PetscSectionGetDof(section, point, &dof)); 6585 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6586 if (!cdof || setBC) { 6587 for (k = 0; k < dof; ++k) { 6588 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6589 const PetscInt ind = indperm ? indperm[preind] : preind; 6590 6591 indices[ind] = off + k; 6592 } 6593 } else { 6594 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6595 for (k = 0; k < dof; ++k) { 6596 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6597 const PetscInt ind = indperm ? indperm[preind] : preind; 6598 6599 if ((cind < cdof) && (k == cdofs[cind])) { 6600 /* Insert check for returning constrained indices */ 6601 indices[ind] = -(off+k+1); 6602 ++cind; 6603 } else { 6604 indices[ind] = off + k - (islocal ? 0 : cind); 6605 } 6606 } 6607 } 6608 *loff += dof; 6609 PetscFunctionReturn(0); 6610 } 6611 6612 /* 6613 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6614 6615 Input Parameters: 6616 + section - a section (global or local) 6617 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6618 . point - point within section 6619 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6620 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6621 . setBC - identify constrained (boundary condition) points via involution. 6622 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6623 . permsoff - offset 6624 - indperm - index permutation 6625 6626 Output Parameter: 6627 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6628 . indices - array to hold indices (as defined by section) of each dof associated with point 6629 6630 Notes: 6631 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6632 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6633 in the local vector. 6634 6635 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6636 significant). It is invalid to call with a global section and setBC=true. 6637 6638 Developer Note: 6639 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6640 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6641 offset could be obtained from the section instead of passing it explicitly as we do now. 6642 6643 Example: 6644 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6645 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6646 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6647 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. 6648 6649 Level: developer 6650 */ 6651 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[]) 6652 { 6653 PetscInt numFields, foff, f; 6654 6655 PetscFunctionBegin; 6656 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6657 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6658 for (f = 0, foff = 0; f < numFields; ++f) { 6659 PetscInt fdof, cfdof; 6660 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6661 PetscInt cind = 0, b; 6662 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6663 6664 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6665 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6666 if (!cfdof || setBC) { 6667 for (b = 0; b < fdof; ++b) { 6668 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6669 const PetscInt ind = indperm ? indperm[preind] : preind; 6670 6671 indices[ind] = off+foff+b; 6672 } 6673 } else { 6674 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6675 for (b = 0; b < fdof; ++b) { 6676 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6677 const PetscInt ind = indperm ? indperm[preind] : preind; 6678 6679 if ((cind < cfdof) && (b == fcdofs[cind])) { 6680 indices[ind] = -(off+foff+b+1); 6681 ++cind; 6682 } else { 6683 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6684 } 6685 } 6686 } 6687 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6688 foffs[f] += fdof; 6689 } 6690 PetscFunctionReturn(0); 6691 } 6692 6693 /* 6694 This version believes the globalSection offsets for each field, rather than just the point offset 6695 6696 . foffs - The offset into 'indices' for each field, since it is segregated by field 6697 6698 Notes: 6699 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6700 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6701 */ 6702 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6703 { 6704 PetscInt numFields, foff, f; 6705 6706 PetscFunctionBegin; 6707 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6708 for (f = 0; f < numFields; ++f) { 6709 PetscInt fdof, cfdof; 6710 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6711 PetscInt cind = 0, b; 6712 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6713 6714 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6715 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6716 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6717 if (!cfdof) { 6718 for (b = 0; b < fdof; ++b) { 6719 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6720 const PetscInt ind = indperm ? indperm[preind] : preind; 6721 6722 indices[ind] = foff+b; 6723 } 6724 } else { 6725 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6726 for (b = 0; b < fdof; ++b) { 6727 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6728 const PetscInt ind = indperm ? indperm[preind] : preind; 6729 6730 if ((cind < cfdof) && (b == fcdofs[cind])) { 6731 indices[ind] = -(foff+b+1); 6732 ++cind; 6733 } else { 6734 indices[ind] = foff+b-cind; 6735 } 6736 } 6737 } 6738 foffs[f] += fdof; 6739 } 6740 PetscFunctionReturn(0); 6741 } 6742 6743 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) 6744 { 6745 Mat cMat; 6746 PetscSection aSec, cSec; 6747 IS aIS; 6748 PetscInt aStart = -1, aEnd = -1; 6749 const PetscInt *anchors; 6750 PetscInt numFields, f, p, q, newP = 0; 6751 PetscInt newNumPoints = 0, newNumIndices = 0; 6752 PetscInt *newPoints, *indices, *newIndices; 6753 PetscInt maxAnchor, maxDof; 6754 PetscInt newOffsets[32]; 6755 PetscInt *pointMatOffsets[32]; 6756 PetscInt *newPointOffsets[32]; 6757 PetscScalar *pointMat[32]; 6758 PetscScalar *newValues=NULL,*tmpValues; 6759 PetscBool anyConstrained = PETSC_FALSE; 6760 6761 PetscFunctionBegin; 6762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6763 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6764 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6765 6766 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6767 /* if there are point-to-point constraints */ 6768 if (aSec) { 6769 PetscCall(PetscArrayzero(newOffsets, 32)); 6770 PetscCall(ISGetIndices(aIS,&anchors)); 6771 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6772 /* figure out how many points are going to be in the new element matrix 6773 * (we allow double counting, because it's all just going to be summed 6774 * into the global matrix anyway) */ 6775 for (p = 0; p < 2*numPoints; p+=2) { 6776 PetscInt b = points[p]; 6777 PetscInt bDof = 0, bSecDof; 6778 6779 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6780 if (!bSecDof) { 6781 continue; 6782 } 6783 if (b >= aStart && b < aEnd) { 6784 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6785 } 6786 if (bDof) { 6787 /* this point is constrained */ 6788 /* it is going to be replaced by its anchors */ 6789 PetscInt bOff, q; 6790 6791 anyConstrained = PETSC_TRUE; 6792 newNumPoints += bDof; 6793 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6794 for (q = 0; q < bDof; q++) { 6795 PetscInt a = anchors[bOff + q]; 6796 PetscInt aDof; 6797 6798 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6799 newNumIndices += aDof; 6800 for (f = 0; f < numFields; ++f) { 6801 PetscInt fDof; 6802 6803 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6804 newOffsets[f+1] += fDof; 6805 } 6806 } 6807 } 6808 else { 6809 /* this point is not constrained */ 6810 newNumPoints++; 6811 newNumIndices += bSecDof; 6812 for (f = 0; f < numFields; ++f) { 6813 PetscInt fDof; 6814 6815 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6816 newOffsets[f+1] += fDof; 6817 } 6818 } 6819 } 6820 } 6821 if (!anyConstrained) { 6822 if (outNumPoints) *outNumPoints = 0; 6823 if (outNumIndices) *outNumIndices = 0; 6824 if (outPoints) *outPoints = NULL; 6825 if (outValues) *outValues = NULL; 6826 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6827 PetscFunctionReturn(0); 6828 } 6829 6830 if (outNumPoints) *outNumPoints = newNumPoints; 6831 if (outNumIndices) *outNumIndices = newNumIndices; 6832 6833 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6834 6835 if (!outPoints && !outValues) { 6836 if (offsets) { 6837 for (f = 0; f <= numFields; f++) { 6838 offsets[f] = newOffsets[f]; 6839 } 6840 } 6841 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6842 PetscFunctionReturn(0); 6843 } 6844 6845 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6846 6847 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6848 6849 /* workspaces */ 6850 if (numFields) { 6851 for (f = 0; f < numFields; f++) { 6852 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6853 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6854 } 6855 } 6856 else { 6857 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6858 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6859 } 6860 6861 /* get workspaces for the point-to-point matrices */ 6862 if (numFields) { 6863 PetscInt totalOffset, totalMatOffset; 6864 6865 for (p = 0; p < numPoints; p++) { 6866 PetscInt b = points[2*p]; 6867 PetscInt bDof = 0, bSecDof; 6868 6869 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6870 if (!bSecDof) { 6871 for (f = 0; f < numFields; f++) { 6872 newPointOffsets[f][p + 1] = 0; 6873 pointMatOffsets[f][p + 1] = 0; 6874 } 6875 continue; 6876 } 6877 if (b >= aStart && b < aEnd) { 6878 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6879 } 6880 if (bDof) { 6881 for (f = 0; f < numFields; f++) { 6882 PetscInt fDof, q, bOff, allFDof = 0; 6883 6884 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6885 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6886 for (q = 0; q < bDof; q++) { 6887 PetscInt a = anchors[bOff + q]; 6888 PetscInt aFDof; 6889 6890 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6891 allFDof += aFDof; 6892 } 6893 newPointOffsets[f][p+1] = allFDof; 6894 pointMatOffsets[f][p+1] = fDof * allFDof; 6895 } 6896 } 6897 else { 6898 for (f = 0; f < numFields; f++) { 6899 PetscInt fDof; 6900 6901 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6902 newPointOffsets[f][p+1] = fDof; 6903 pointMatOffsets[f][p+1] = 0; 6904 } 6905 } 6906 } 6907 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6908 newPointOffsets[f][0] = totalOffset; 6909 pointMatOffsets[f][0] = totalMatOffset; 6910 for (p = 0; p < numPoints; p++) { 6911 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6912 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6913 } 6914 totalOffset = newPointOffsets[f][numPoints]; 6915 totalMatOffset = pointMatOffsets[f][numPoints]; 6916 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6917 } 6918 } 6919 else { 6920 for (p = 0; p < numPoints; p++) { 6921 PetscInt b = points[2*p]; 6922 PetscInt bDof = 0, bSecDof; 6923 6924 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6925 if (!bSecDof) { 6926 newPointOffsets[0][p + 1] = 0; 6927 pointMatOffsets[0][p + 1] = 0; 6928 continue; 6929 } 6930 if (b >= aStart && b < aEnd) { 6931 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6932 } 6933 if (bDof) { 6934 PetscInt bOff, q, allDof = 0; 6935 6936 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6937 for (q = 0; q < bDof; q++) { 6938 PetscInt a = anchors[bOff + q], aDof; 6939 6940 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6941 allDof += aDof; 6942 } 6943 newPointOffsets[0][p+1] = allDof; 6944 pointMatOffsets[0][p+1] = bSecDof * allDof; 6945 } 6946 else { 6947 newPointOffsets[0][p+1] = bSecDof; 6948 pointMatOffsets[0][p+1] = 0; 6949 } 6950 } 6951 newPointOffsets[0][0] = 0; 6952 pointMatOffsets[0][0] = 0; 6953 for (p = 0; p < numPoints; p++) { 6954 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6955 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6956 } 6957 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6958 } 6959 6960 /* output arrays */ 6961 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6962 6963 /* get the point-to-point matrices; construct newPoints */ 6964 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6965 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6966 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6967 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6968 if (numFields) { 6969 for (p = 0, newP = 0; p < numPoints; p++) { 6970 PetscInt b = points[2*p]; 6971 PetscInt o = points[2*p+1]; 6972 PetscInt bDof = 0, bSecDof; 6973 6974 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6975 if (!bSecDof) { 6976 continue; 6977 } 6978 if (b >= aStart && b < aEnd) { 6979 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6980 } 6981 if (bDof) { 6982 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6983 6984 fStart[0] = 0; 6985 fEnd[0] = 0; 6986 for (f = 0; f < numFields; f++) { 6987 PetscInt fDof; 6988 6989 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6990 fStart[f+1] = fStart[f] + fDof; 6991 fEnd[f+1] = fStart[f+1]; 6992 } 6993 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6994 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6995 6996 fAnchorStart[0] = 0; 6997 fAnchorEnd[0] = 0; 6998 for (f = 0; f < numFields; f++) { 6999 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7000 7001 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7002 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7003 } 7004 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7005 for (q = 0; q < bDof; q++) { 7006 PetscInt a = anchors[bOff + q], aOff; 7007 7008 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7009 newPoints[2*(newP + q)] = a; 7010 newPoints[2*(newP + q) + 1] = 0; 7011 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7012 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7013 } 7014 newP += bDof; 7015 7016 if (outValues) { 7017 /* get the point-to-point submatrix */ 7018 for (f = 0; f < numFields; f++) { 7019 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7020 } 7021 } 7022 } 7023 else { 7024 newPoints[2 * newP] = b; 7025 newPoints[2 * newP + 1] = o; 7026 newP++; 7027 } 7028 } 7029 } else { 7030 for (p = 0; p < numPoints; p++) { 7031 PetscInt b = points[2*p]; 7032 PetscInt o = points[2*p+1]; 7033 PetscInt bDof = 0, bSecDof; 7034 7035 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7036 if (!bSecDof) { 7037 continue; 7038 } 7039 if (b >= aStart && b < aEnd) { 7040 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7041 } 7042 if (bDof) { 7043 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7044 7045 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7046 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7047 7048 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7049 for (q = 0; q < bDof; q++) { 7050 PetscInt a = anchors[bOff + q], aOff; 7051 7052 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7053 7054 newPoints[2*(newP + q)] = a; 7055 newPoints[2*(newP + q) + 1] = 0; 7056 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7057 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7058 } 7059 newP += bDof; 7060 7061 /* get the point-to-point submatrix */ 7062 if (outValues) { 7063 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7064 } 7065 } 7066 else { 7067 newPoints[2 * newP] = b; 7068 newPoints[2 * newP + 1] = o; 7069 newP++; 7070 } 7071 } 7072 } 7073 7074 if (outValues) { 7075 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7076 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7077 /* multiply constraints on the right */ 7078 if (numFields) { 7079 for (f = 0; f < numFields; f++) { 7080 PetscInt oldOff = offsets[f]; 7081 7082 for (p = 0; p < numPoints; p++) { 7083 PetscInt cStart = newPointOffsets[f][p]; 7084 PetscInt b = points[2 * p]; 7085 PetscInt c, r, k; 7086 PetscInt dof; 7087 7088 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7089 if (!dof) { 7090 continue; 7091 } 7092 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7093 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7094 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7095 7096 for (r = 0; r < numIndices; r++) { 7097 for (c = 0; c < nCols; c++) { 7098 for (k = 0; k < dof; k++) { 7099 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7100 } 7101 } 7102 } 7103 } 7104 else { 7105 /* copy this column as is */ 7106 for (r = 0; r < numIndices; r++) { 7107 for (c = 0; c < dof; c++) { 7108 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7109 } 7110 } 7111 } 7112 oldOff += dof; 7113 } 7114 } 7115 } 7116 else { 7117 PetscInt oldOff = 0; 7118 for (p = 0; p < numPoints; p++) { 7119 PetscInt cStart = newPointOffsets[0][p]; 7120 PetscInt b = points[2 * p]; 7121 PetscInt c, r, k; 7122 PetscInt dof; 7123 7124 PetscCall(PetscSectionGetDof(section,b,&dof)); 7125 if (!dof) { 7126 continue; 7127 } 7128 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7129 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7130 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7131 7132 for (r = 0; r < numIndices; r++) { 7133 for (c = 0; c < nCols; c++) { 7134 for (k = 0; k < dof; k++) { 7135 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7136 } 7137 } 7138 } 7139 } 7140 else { 7141 /* copy this column as is */ 7142 for (r = 0; r < numIndices; r++) { 7143 for (c = 0; c < dof; c++) { 7144 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7145 } 7146 } 7147 } 7148 oldOff += dof; 7149 } 7150 } 7151 7152 if (multiplyLeft) { 7153 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7154 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7155 /* multiply constraints transpose on the left */ 7156 if (numFields) { 7157 for (f = 0; f < numFields; f++) { 7158 PetscInt oldOff = offsets[f]; 7159 7160 for (p = 0; p < numPoints; p++) { 7161 PetscInt rStart = newPointOffsets[f][p]; 7162 PetscInt b = points[2 * p]; 7163 PetscInt c, r, k; 7164 PetscInt dof; 7165 7166 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7167 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7168 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7169 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7170 7171 for (r = 0; r < nRows; r++) { 7172 for (c = 0; c < newNumIndices; c++) { 7173 for (k = 0; k < dof; k++) { 7174 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7175 } 7176 } 7177 } 7178 } 7179 else { 7180 /* copy this row as is */ 7181 for (r = 0; r < dof; r++) { 7182 for (c = 0; c < newNumIndices; c++) { 7183 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7184 } 7185 } 7186 } 7187 oldOff += dof; 7188 } 7189 } 7190 } 7191 else { 7192 PetscInt oldOff = 0; 7193 7194 for (p = 0; p < numPoints; p++) { 7195 PetscInt rStart = newPointOffsets[0][p]; 7196 PetscInt b = points[2 * p]; 7197 PetscInt c, r, k; 7198 PetscInt dof; 7199 7200 PetscCall(PetscSectionGetDof(section,b,&dof)); 7201 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7202 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7203 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7204 7205 for (r = 0; r < nRows; r++) { 7206 for (c = 0; c < newNumIndices; c++) { 7207 for (k = 0; k < dof; k++) { 7208 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7209 } 7210 } 7211 } 7212 } 7213 else { 7214 /* copy this row as is */ 7215 for (r = 0; r < dof; r++) { 7216 for (c = 0; c < newNumIndices; c++) { 7217 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7218 } 7219 } 7220 } 7221 oldOff += dof; 7222 } 7223 } 7224 7225 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7226 } 7227 else { 7228 newValues = tmpValues; 7229 } 7230 } 7231 7232 /* clean up */ 7233 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7234 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7235 7236 if (numFields) { 7237 for (f = 0; f < numFields; f++) { 7238 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7239 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7240 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7241 } 7242 } 7243 else { 7244 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7245 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7246 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7247 } 7248 PetscCall(ISRestoreIndices(aIS,&anchors)); 7249 7250 /* output */ 7251 if (outPoints) { 7252 *outPoints = newPoints; 7253 } 7254 else { 7255 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7256 } 7257 if (outValues) { 7258 *outValues = newValues; 7259 } 7260 for (f = 0; f <= numFields; f++) { 7261 offsets[f] = newOffsets[f]; 7262 } 7263 PetscFunctionReturn(0); 7264 } 7265 7266 /*@C 7267 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7268 7269 Not collective 7270 7271 Input Parameters: 7272 + dm - The DM 7273 . section - The PetscSection describing the points (a local section) 7274 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7275 . point - The point defining the closure 7276 - useClPerm - Use the closure point permutation if available 7277 7278 Output Parameters: 7279 + numIndices - The number of dof indices in the closure of point with the input sections 7280 . indices - The dof indices 7281 . outOffsets - Array to write the field offsets into, or NULL 7282 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7283 7284 Notes: 7285 Must call DMPlexRestoreClosureIndices() to free allocated memory 7286 7287 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7288 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7289 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7290 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7291 indices (with the above semantics) are implied. 7292 7293 Level: advanced 7294 7295 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7296 @*/ 7297 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7298 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7299 { 7300 /* Closure ordering */ 7301 PetscSection clSection; 7302 IS clPoints; 7303 const PetscInt *clp; 7304 PetscInt *points; 7305 const PetscInt *clperm = NULL; 7306 /* Dof permutation and sign flips */ 7307 const PetscInt **perms[32] = {NULL}; 7308 const PetscScalar **flips[32] = {NULL}; 7309 PetscScalar *valCopy = NULL; 7310 /* Hanging node constraints */ 7311 PetscInt *pointsC = NULL; 7312 PetscScalar *valuesC = NULL; 7313 PetscInt NclC, NiC; 7314 7315 PetscInt *idx; 7316 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7317 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7318 7319 PetscFunctionBeginHot; 7320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7321 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7322 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7323 if (numIndices) PetscValidIntPointer(numIndices, 6); 7324 if (indices) PetscValidPointer(indices, 7); 7325 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7326 if (values) PetscValidPointer(values, 9); 7327 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7328 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7329 PetscCall(PetscArrayzero(offsets, 32)); 7330 /* 1) Get points in closure */ 7331 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7332 if (useClPerm) { 7333 PetscInt depth, clsize; 7334 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7335 for (clsize=0,p=0; p<Ncl; p++) { 7336 PetscInt dof; 7337 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7338 clsize += dof; 7339 } 7340 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7341 } 7342 /* 2) Get number of indices on these points and field offsets from section */ 7343 for (p = 0; p < Ncl*2; p += 2) { 7344 PetscInt dof, fdof; 7345 7346 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7347 for (f = 0; f < Nf; ++f) { 7348 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7349 offsets[f+1] += fdof; 7350 } 7351 Ni += dof; 7352 } 7353 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7354 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7355 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7356 for (f = 0; f < PetscMax(1, Nf); ++f) { 7357 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7358 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7359 /* may need to apply sign changes to the element matrix */ 7360 if (values && flips[f]) { 7361 PetscInt foffset = offsets[f]; 7362 7363 for (p = 0; p < Ncl; ++p) { 7364 PetscInt pnt = points[2*p], fdof; 7365 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7366 7367 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7368 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7369 if (flip) { 7370 PetscInt i, j, k; 7371 7372 if (!valCopy) { 7373 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7374 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7375 *values = valCopy; 7376 } 7377 for (i = 0; i < fdof; ++i) { 7378 PetscScalar fval = flip[i]; 7379 7380 for (k = 0; k < Ni; ++k) { 7381 valCopy[Ni * (foffset + i) + k] *= fval; 7382 valCopy[Ni * k + (foffset + i)] *= fval; 7383 } 7384 } 7385 } 7386 foffset += fdof; 7387 } 7388 } 7389 } 7390 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7391 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7392 if (NclC) { 7393 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7394 for (f = 0; f < PetscMax(1, Nf); ++f) { 7395 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7396 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7397 } 7398 for (f = 0; f < PetscMax(1, Nf); ++f) { 7399 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7400 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7401 } 7402 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7403 Ncl = NclC; 7404 Ni = NiC; 7405 points = pointsC; 7406 if (values) *values = valuesC; 7407 } 7408 /* 5) Calculate indices */ 7409 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7410 if (Nf) { 7411 PetscInt idxOff; 7412 PetscBool useFieldOffsets; 7413 7414 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7415 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7416 if (useFieldOffsets) { 7417 for (p = 0; p < Ncl; ++p) { 7418 const PetscInt pnt = points[p*2]; 7419 7420 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7421 } 7422 } else { 7423 for (p = 0; p < Ncl; ++p) { 7424 const PetscInt pnt = points[p*2]; 7425 7426 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7427 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7428 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7429 * global section. */ 7430 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7431 } 7432 } 7433 } else { 7434 PetscInt off = 0, idxOff; 7435 7436 for (p = 0; p < Ncl; ++p) { 7437 const PetscInt pnt = points[p*2]; 7438 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7439 7440 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7441 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7442 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7443 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7444 } 7445 } 7446 /* 6) Cleanup */ 7447 for (f = 0; f < PetscMax(1, Nf); ++f) { 7448 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7449 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7450 } 7451 if (NclC) { 7452 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7453 } else { 7454 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7455 } 7456 7457 if (numIndices) *numIndices = Ni; 7458 if (indices) *indices = idx; 7459 PetscFunctionReturn(0); 7460 } 7461 7462 /*@C 7463 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7464 7465 Not collective 7466 7467 Input Parameters: 7468 + dm - The DM 7469 . section - The PetscSection describing the points (a local section) 7470 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7471 . point - The point defining the closure 7472 - useClPerm - Use the closure point permutation if available 7473 7474 Output Parameters: 7475 + numIndices - The number of dof indices in the closure of point with the input sections 7476 . indices - The dof indices 7477 . outOffsets - Array to write the field offsets into, or NULL 7478 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7479 7480 Notes: 7481 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7482 7483 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7484 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7485 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7486 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7487 indices (with the above semantics) are implied. 7488 7489 Level: advanced 7490 7491 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7492 @*/ 7493 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7494 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7495 { 7496 PetscFunctionBegin; 7497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7498 PetscValidPointer(indices, 7); 7499 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7500 PetscFunctionReturn(0); 7501 } 7502 7503 /*@C 7504 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7505 7506 Not collective 7507 7508 Input Parameters: 7509 + dm - The DM 7510 . section - The section describing the layout in v, or NULL to use the default section 7511 . globalSection - The section describing the layout in v, or NULL to use the default global section 7512 . A - The matrix 7513 . point - The point in the DM 7514 . values - The array of values 7515 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7516 7517 Fortran Notes: 7518 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7519 7520 Level: intermediate 7521 7522 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7523 @*/ 7524 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7525 { 7526 DM_Plex *mesh = (DM_Plex*) dm->data; 7527 PetscInt *indices; 7528 PetscInt numIndices; 7529 const PetscScalar *valuesOrig = values; 7530 PetscErrorCode ierr; 7531 7532 PetscFunctionBegin; 7533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7534 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7535 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7536 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7537 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7538 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7539 7540 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7541 7542 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7543 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7544 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7545 if (ierr) { 7546 PetscMPIInt rank; 7547 7548 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7549 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7550 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7551 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7552 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7553 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7554 } 7555 if (mesh->printFEM > 1) { 7556 PetscInt i; 7557 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7558 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7559 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7560 } 7561 7562 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7563 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7564 PetscFunctionReturn(0); 7565 } 7566 7567 /*@C 7568 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7569 7570 Not collective 7571 7572 Input Parameters: 7573 + dmRow - The DM for the row fields 7574 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7575 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7576 . dmCol - The DM for the column fields 7577 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7578 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7579 . A - The matrix 7580 . point - The point in the DMs 7581 . values - The array of values 7582 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7583 7584 Level: intermediate 7585 7586 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7587 @*/ 7588 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7589 { 7590 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7591 PetscInt *indicesRow, *indicesCol; 7592 PetscInt numIndicesRow, numIndicesCol; 7593 const PetscScalar *valuesOrig = values; 7594 PetscErrorCode ierr; 7595 7596 PetscFunctionBegin; 7597 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7598 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7599 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7600 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7601 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7602 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7603 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7604 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7605 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7606 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7607 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7608 7609 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7610 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7611 7612 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7613 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7614 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7615 if (ierr) { 7616 PetscMPIInt rank; 7617 7618 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7619 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7620 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7621 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7622 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7623 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7624 } 7625 7626 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7627 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7628 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7629 PetscFunctionReturn(0); 7630 } 7631 7632 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7633 { 7634 DM_Plex *mesh = (DM_Plex*) dmf->data; 7635 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7636 PetscInt *cpoints = NULL; 7637 PetscInt *findices, *cindices; 7638 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7639 PetscInt foffsets[32], coffsets[32]; 7640 DMPolytopeType ct; 7641 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7642 PetscErrorCode ierr; 7643 7644 PetscFunctionBegin; 7645 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7646 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7647 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7648 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7649 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7650 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7651 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7652 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7653 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7654 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7655 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7656 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7657 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7658 PetscCall(PetscArrayzero(foffsets, 32)); 7659 PetscCall(PetscArrayzero(coffsets, 32)); 7660 /* Column indices */ 7661 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7662 maxFPoints = numCPoints; 7663 /* Compress out points not in the section */ 7664 /* TODO: Squeeze out points with 0 dof as well */ 7665 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7666 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7667 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7668 cpoints[q*2] = cpoints[p]; 7669 cpoints[q*2+1] = cpoints[p+1]; 7670 ++q; 7671 } 7672 } 7673 numCPoints = q; 7674 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7675 PetscInt fdof; 7676 7677 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7678 if (!dof) continue; 7679 for (f = 0; f < numFields; ++f) { 7680 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7681 coffsets[f+1] += fdof; 7682 } 7683 numCIndices += dof; 7684 } 7685 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7686 /* Row indices */ 7687 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7688 { 7689 DMPlexTransform tr; 7690 DMPolytopeType *rct; 7691 PetscInt *rsize, *rcone, *rornt, Nt; 7692 7693 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7694 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7695 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7696 numSubcells = rsize[Nt-1]; 7697 PetscCall(DMPlexTransformDestroy(&tr)); 7698 } 7699 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7700 for (r = 0, q = 0; r < numSubcells; ++r) { 7701 /* TODO Map from coarse to fine cells */ 7702 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7703 /* Compress out points not in the section */ 7704 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7705 for (p = 0; p < numFPoints*2; p += 2) { 7706 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7707 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7708 if (!dof) continue; 7709 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7710 if (s < q) continue; 7711 ftotpoints[q*2] = fpoints[p]; 7712 ftotpoints[q*2+1] = fpoints[p+1]; 7713 ++q; 7714 } 7715 } 7716 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7717 } 7718 numFPoints = q; 7719 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7720 PetscInt fdof; 7721 7722 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7723 if (!dof) continue; 7724 for (f = 0; f < numFields; ++f) { 7725 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7726 foffsets[f+1] += fdof; 7727 } 7728 numFIndices += dof; 7729 } 7730 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7731 7732 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7733 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7734 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7735 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7736 if (numFields) { 7737 const PetscInt **permsF[32] = {NULL}; 7738 const PetscInt **permsC[32] = {NULL}; 7739 7740 for (f = 0; f < numFields; f++) { 7741 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7742 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7743 } 7744 for (p = 0; p < numFPoints; p++) { 7745 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7746 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7747 } 7748 for (p = 0; p < numCPoints; p++) { 7749 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7750 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7751 } 7752 for (f = 0; f < numFields; f++) { 7753 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7754 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7755 } 7756 } else { 7757 const PetscInt **permsF = NULL; 7758 const PetscInt **permsC = NULL; 7759 7760 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7761 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7762 for (p = 0, off = 0; p < numFPoints; p++) { 7763 const PetscInt *perm = permsF ? permsF[p] : NULL; 7764 7765 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7766 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7767 } 7768 for (p = 0, off = 0; p < numCPoints; p++) { 7769 const PetscInt *perm = permsC ? permsC[p] : NULL; 7770 7771 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7772 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7773 } 7774 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7775 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7776 } 7777 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7778 /* TODO: flips */ 7779 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7780 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7781 if (ierr) { 7782 PetscMPIInt rank; 7783 7784 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7785 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7786 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7787 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7788 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7789 } 7790 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7791 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7792 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7793 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7794 PetscFunctionReturn(0); 7795 } 7796 7797 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7798 { 7799 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7800 PetscInt *cpoints = NULL; 7801 PetscInt foffsets[32], coffsets[32]; 7802 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7803 DMPolytopeType ct; 7804 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7805 7806 PetscFunctionBegin; 7807 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7808 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7809 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7810 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7811 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7812 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7813 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7814 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7815 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7816 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7817 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7818 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7819 PetscCall(PetscArrayzero(foffsets, 32)); 7820 PetscCall(PetscArrayzero(coffsets, 32)); 7821 /* Column indices */ 7822 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7823 maxFPoints = numCPoints; 7824 /* Compress out points not in the section */ 7825 /* TODO: Squeeze out points with 0 dof as well */ 7826 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7827 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7828 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7829 cpoints[q*2] = cpoints[p]; 7830 cpoints[q*2+1] = cpoints[p+1]; 7831 ++q; 7832 } 7833 } 7834 numCPoints = q; 7835 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7836 PetscInt fdof; 7837 7838 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7839 if (!dof) continue; 7840 for (f = 0; f < numFields; ++f) { 7841 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7842 coffsets[f+1] += fdof; 7843 } 7844 numCIndices += dof; 7845 } 7846 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7847 /* Row indices */ 7848 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7849 { 7850 DMPlexTransform tr; 7851 DMPolytopeType *rct; 7852 PetscInt *rsize, *rcone, *rornt, Nt; 7853 7854 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7855 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7856 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7857 numSubcells = rsize[Nt-1]; 7858 PetscCall(DMPlexTransformDestroy(&tr)); 7859 } 7860 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7861 for (r = 0, q = 0; r < numSubcells; ++r) { 7862 /* TODO Map from coarse to fine cells */ 7863 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7864 /* Compress out points not in the section */ 7865 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7866 for (p = 0; p < numFPoints*2; p += 2) { 7867 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7868 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7869 if (!dof) continue; 7870 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7871 if (s < q) continue; 7872 ftotpoints[q*2] = fpoints[p]; 7873 ftotpoints[q*2+1] = fpoints[p+1]; 7874 ++q; 7875 } 7876 } 7877 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7878 } 7879 numFPoints = q; 7880 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7881 PetscInt fdof; 7882 7883 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7884 if (!dof) continue; 7885 for (f = 0; f < numFields; ++f) { 7886 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7887 foffsets[f+1] += fdof; 7888 } 7889 numFIndices += dof; 7890 } 7891 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7892 7893 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7894 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7895 if (numFields) { 7896 const PetscInt **permsF[32] = {NULL}; 7897 const PetscInt **permsC[32] = {NULL}; 7898 7899 for (f = 0; f < numFields; f++) { 7900 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7901 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7902 } 7903 for (p = 0; p < numFPoints; p++) { 7904 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7905 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7906 } 7907 for (p = 0; p < numCPoints; p++) { 7908 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7909 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7910 } 7911 for (f = 0; f < numFields; f++) { 7912 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7913 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7914 } 7915 } else { 7916 const PetscInt **permsF = NULL; 7917 const PetscInt **permsC = NULL; 7918 7919 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7920 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7921 for (p = 0, off = 0; p < numFPoints; p++) { 7922 const PetscInt *perm = permsF ? permsF[p] : NULL; 7923 7924 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7925 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7926 } 7927 for (p = 0, off = 0; p < numCPoints; p++) { 7928 const PetscInt *perm = permsC ? permsC[p] : NULL; 7929 7930 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7931 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7932 } 7933 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7934 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7935 } 7936 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7937 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7938 PetscFunctionReturn(0); 7939 } 7940 7941 /*@C 7942 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7943 7944 Input Parameter: 7945 . dm - The DMPlex object 7946 7947 Output Parameter: 7948 . cellHeight - The height of a cell 7949 7950 Level: developer 7951 7952 .seealso `DMPlexSetVTKCellHeight()` 7953 @*/ 7954 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7955 { 7956 DM_Plex *mesh = (DM_Plex*) dm->data; 7957 7958 PetscFunctionBegin; 7959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7960 PetscValidIntPointer(cellHeight, 2); 7961 *cellHeight = mesh->vtkCellHeight; 7962 PetscFunctionReturn(0); 7963 } 7964 7965 /*@C 7966 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7967 7968 Input Parameters: 7969 + dm - The DMPlex object 7970 - cellHeight - The height of a cell 7971 7972 Level: developer 7973 7974 .seealso `DMPlexGetVTKCellHeight()` 7975 @*/ 7976 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7977 { 7978 DM_Plex *mesh = (DM_Plex*) dm->data; 7979 7980 PetscFunctionBegin; 7981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7982 mesh->vtkCellHeight = cellHeight; 7983 PetscFunctionReturn(0); 7984 } 7985 7986 /*@ 7987 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7988 7989 Input Parameter: 7990 . dm - The DMPlex object 7991 7992 Output Parameters: 7993 + gcStart - The first ghost cell, or NULL 7994 - gcEnd - The upper bound on ghost cells, or NULL 7995 7996 Level: advanced 7997 7998 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7999 @*/ 8000 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8001 { 8002 DMLabel ctLabel; 8003 8004 PetscFunctionBegin; 8005 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8006 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8007 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8008 // Reset label for fast lookup 8009 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8010 PetscFunctionReturn(0); 8011 } 8012 8013 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8014 { 8015 PetscSection section, globalSection; 8016 PetscInt *numbers, p; 8017 8018 PetscFunctionBegin; 8019 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8020 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8021 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8022 for (p = pStart; p < pEnd; ++p) { 8023 PetscCall(PetscSectionSetDof(section, p, 1)); 8024 } 8025 PetscCall(PetscSectionSetUp(section)); 8026 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8027 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8028 for (p = pStart; p < pEnd; ++p) { 8029 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8030 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8031 else numbers[p-pStart] += shift; 8032 } 8033 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8034 if (globalSize) { 8035 PetscLayout layout; 8036 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8037 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8038 PetscCall(PetscLayoutDestroy(&layout)); 8039 } 8040 PetscCall(PetscSectionDestroy(§ion)); 8041 PetscCall(PetscSectionDestroy(&globalSection)); 8042 PetscFunctionReturn(0); 8043 } 8044 8045 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8046 { 8047 PetscInt cellHeight, cStart, cEnd; 8048 8049 PetscFunctionBegin; 8050 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8051 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8052 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8053 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8054 PetscFunctionReturn(0); 8055 } 8056 8057 /*@ 8058 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8059 8060 Input Parameter: 8061 . dm - The DMPlex object 8062 8063 Output Parameter: 8064 . globalCellNumbers - Global cell numbers for all cells on this process 8065 8066 Level: developer 8067 8068 .seealso `DMPlexGetVertexNumbering()` 8069 @*/ 8070 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8071 { 8072 DM_Plex *mesh = (DM_Plex*) dm->data; 8073 8074 PetscFunctionBegin; 8075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8076 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8077 *globalCellNumbers = mesh->globalCellNumbers; 8078 PetscFunctionReturn(0); 8079 } 8080 8081 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8082 { 8083 PetscInt vStart, vEnd; 8084 8085 PetscFunctionBegin; 8086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8087 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8088 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8089 PetscFunctionReturn(0); 8090 } 8091 8092 /*@ 8093 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8094 8095 Input Parameter: 8096 . dm - The DMPlex object 8097 8098 Output Parameter: 8099 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8100 8101 Level: developer 8102 8103 .seealso `DMPlexGetCellNumbering()` 8104 @*/ 8105 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8106 { 8107 DM_Plex *mesh = (DM_Plex*) dm->data; 8108 8109 PetscFunctionBegin; 8110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8111 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8112 *globalVertexNumbers = mesh->globalVertexNumbers; 8113 PetscFunctionReturn(0); 8114 } 8115 8116 /*@ 8117 DMPlexCreatePointNumbering - Create a global numbering for all points. 8118 8119 Collective on dm 8120 8121 Input Parameter: 8122 . dm - The DMPlex object 8123 8124 Output Parameter: 8125 . globalPointNumbers - Global numbers for all points on this process 8126 8127 Notes: 8128 8129 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8130 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8131 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8132 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8133 8134 The partitioned mesh is 8135 ``` 8136 (2)--0--(3)--1--(4) (1)--0--(2) 8137 ``` 8138 and its global numbering is 8139 ``` 8140 (3)--0--(4)--1--(5)--2--(6) 8141 ``` 8142 Then the global numbering is provided as 8143 ``` 8144 [0] Number of indices in set 5 8145 [0] 0 0 8146 [0] 1 1 8147 [0] 2 3 8148 [0] 3 4 8149 [0] 4 -6 8150 [1] Number of indices in set 3 8151 [1] 0 2 8152 [1] 1 5 8153 [1] 2 6 8154 ``` 8155 8156 Level: developer 8157 8158 .seealso `DMPlexGetCellNumbering()` 8159 @*/ 8160 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8161 { 8162 IS nums[4]; 8163 PetscInt depths[4], gdepths[4], starts[4]; 8164 PetscInt depth, d, shift = 0; 8165 8166 PetscFunctionBegin; 8167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8168 PetscCall(DMPlexGetDepth(dm, &depth)); 8169 /* For unstratified meshes use dim instead of depth */ 8170 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8171 for (d = 0; d <= depth; ++d) { 8172 PetscInt end; 8173 8174 depths[d] = depth-d; 8175 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8176 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8177 } 8178 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8179 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8180 for (d = 0; d <= depth; ++d) { 8181 PetscCheck(starts[d] < 0 || depths[d] == gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT,depths[d],gdepths[d]); 8182 } 8183 for (d = 0; d <= depth; ++d) { 8184 PetscInt pStart, pEnd, gsize; 8185 8186 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8187 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8188 shift += gsize; 8189 } 8190 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8191 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8192 PetscFunctionReturn(0); 8193 } 8194 8195 /*@ 8196 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8197 8198 Input Parameter: 8199 . dm - The DMPlex object 8200 8201 Output Parameter: 8202 . ranks - The rank field 8203 8204 Options Database Keys: 8205 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8206 8207 Level: intermediate 8208 8209 .seealso: `DMView()` 8210 @*/ 8211 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8212 { 8213 DM rdm; 8214 PetscFE fe; 8215 PetscScalar *r; 8216 PetscMPIInt rank; 8217 DMPolytopeType ct; 8218 PetscInt dim, cStart, cEnd, c; 8219 PetscBool simplex; 8220 8221 PetscFunctionBeginUser; 8222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8223 PetscValidPointer(ranks, 2); 8224 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8225 PetscCall(DMClone(dm, &rdm)); 8226 PetscCall(DMGetDimension(rdm, &dim)); 8227 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8228 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8229 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8230 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8231 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8232 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8233 PetscCall(PetscFEDestroy(&fe)); 8234 PetscCall(DMCreateDS(rdm)); 8235 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8236 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8237 PetscCall(VecGetArray(*ranks, &r)); 8238 for (c = cStart; c < cEnd; ++c) { 8239 PetscScalar *lr; 8240 8241 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8242 if (lr) *lr = rank; 8243 } 8244 PetscCall(VecRestoreArray(*ranks, &r)); 8245 PetscCall(DMDestroy(&rdm)); 8246 PetscFunctionReturn(0); 8247 } 8248 8249 /*@ 8250 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8251 8252 Input Parameters: 8253 + dm - The DMPlex 8254 - label - The DMLabel 8255 8256 Output Parameter: 8257 . val - The label value field 8258 8259 Options Database Keys: 8260 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8261 8262 Level: intermediate 8263 8264 .seealso: `DMView()` 8265 @*/ 8266 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8267 { 8268 DM rdm; 8269 PetscFE fe; 8270 PetscScalar *v; 8271 PetscInt dim, cStart, cEnd, c; 8272 8273 PetscFunctionBeginUser; 8274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8275 PetscValidPointer(label, 2); 8276 PetscValidPointer(val, 3); 8277 PetscCall(DMClone(dm, &rdm)); 8278 PetscCall(DMGetDimension(rdm, &dim)); 8279 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8280 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8281 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8282 PetscCall(PetscFEDestroy(&fe)); 8283 PetscCall(DMCreateDS(rdm)); 8284 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8285 PetscCall(DMCreateGlobalVector(rdm, val)); 8286 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8287 PetscCall(VecGetArray(*val, &v)); 8288 for (c = cStart; c < cEnd; ++c) { 8289 PetscScalar *lv; 8290 PetscInt cval; 8291 8292 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8293 PetscCall(DMLabelGetValue(label, c, &cval)); 8294 *lv = cval; 8295 } 8296 PetscCall(VecRestoreArray(*val, &v)); 8297 PetscCall(DMDestroy(&rdm)); 8298 PetscFunctionReturn(0); 8299 } 8300 8301 /*@ 8302 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8303 8304 Input Parameter: 8305 . dm - The DMPlex object 8306 8307 Notes: 8308 This is a useful diagnostic when creating meshes programmatically. 8309 8310 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8311 8312 Level: developer 8313 8314 .seealso: `DMCreate()`, `DMSetFromOptions()` 8315 @*/ 8316 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8317 { 8318 PetscSection coneSection, supportSection; 8319 const PetscInt *cone, *support; 8320 PetscInt coneSize, c, supportSize, s; 8321 PetscInt pStart, pEnd, p, pp, csize, ssize; 8322 PetscBool storagecheck = PETSC_TRUE; 8323 8324 PetscFunctionBegin; 8325 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8326 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8327 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8328 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8329 /* Check that point p is found in the support of its cone points, and vice versa */ 8330 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8331 for (p = pStart; p < pEnd; ++p) { 8332 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8333 PetscCall(DMPlexGetCone(dm, p, &cone)); 8334 for (c = 0; c < coneSize; ++c) { 8335 PetscBool dup = PETSC_FALSE; 8336 PetscInt d; 8337 for (d = c-1; d >= 0; --d) { 8338 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8339 } 8340 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8341 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8342 for (s = 0; s < supportSize; ++s) { 8343 if (support[s] == p) break; 8344 } 8345 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8346 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8347 for (s = 0; s < coneSize; ++s) { 8348 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8349 } 8350 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8351 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8352 for (s = 0; s < supportSize; ++s) { 8353 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8354 } 8355 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8356 PetscCheck(!dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not repeatedly found in support of repeated cone point %" PetscInt_FMT, p, cone[c]); 8357 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8358 } 8359 } 8360 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8361 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8362 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8363 PetscCall(DMPlexGetSupport(dm, p, &support)); 8364 for (s = 0; s < supportSize; ++s) { 8365 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8366 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8367 for (c = 0; c < coneSize; ++c) { 8368 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8369 if (cone[c] != pp) { c = 0; break; } 8370 if (cone[c] == p) break; 8371 } 8372 if (c >= coneSize) { 8373 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8374 for (c = 0; c < supportSize; ++c) { 8375 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8376 } 8377 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8378 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8379 for (c = 0; c < coneSize; ++c) { 8380 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8381 } 8382 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8383 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8384 } 8385 } 8386 } 8387 if (storagecheck) { 8388 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8389 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8390 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8391 } 8392 PetscFunctionReturn(0); 8393 } 8394 8395 /* 8396 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. 8397 */ 8398 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8399 { 8400 DMPolytopeType cct; 8401 PetscInt ptpoints[4]; 8402 const PetscInt *cone, *ccone, *ptcone; 8403 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8404 8405 PetscFunctionBegin; 8406 *unsplit = 0; 8407 switch (ct) { 8408 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8409 ptpoints[npt++] = c; 8410 break; 8411 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8412 PetscCall(DMPlexGetCone(dm, c, &cone)); 8413 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8414 for (cp = 0; cp < coneSize; ++cp) { 8415 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8416 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8417 } 8418 break; 8419 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8420 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8421 PetscCall(DMPlexGetCone(dm, c, &cone)); 8422 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8423 for (cp = 0; cp < coneSize; ++cp) { 8424 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8425 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8426 for (ccp = 0; ccp < cconeSize; ++ccp) { 8427 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8428 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8429 PetscInt p; 8430 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8431 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8432 } 8433 } 8434 } 8435 break; 8436 default: break; 8437 } 8438 for (pt = 0; pt < npt; ++pt) { 8439 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8440 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8441 } 8442 PetscFunctionReturn(0); 8443 } 8444 8445 /*@ 8446 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8447 8448 Input Parameters: 8449 + dm - The DMPlex object 8450 - cellHeight - Normally 0 8451 8452 Notes: 8453 This is a useful diagnostic when creating meshes programmatically. 8454 Currently applicable only to homogeneous simplex or tensor meshes. 8455 8456 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8457 8458 Level: developer 8459 8460 .seealso: `DMCreate()`, `DMSetFromOptions()` 8461 @*/ 8462 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8463 { 8464 DMPlexInterpolatedFlag interp; 8465 DMPolytopeType ct; 8466 PetscInt vStart, vEnd, cStart, cEnd, c; 8467 8468 PetscFunctionBegin; 8469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8470 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8471 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8472 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8473 for (c = cStart; c < cEnd; ++c) { 8474 PetscInt *closure = NULL; 8475 PetscInt coneSize, closureSize, cl, Nv = 0; 8476 8477 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8478 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8479 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8480 if (interp == DMPLEX_INTERPOLATED_FULL) { 8481 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8482 PetscCheck(coneSize == DMPolytopeTypeGetConeSize(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has cone size %" PetscInt_FMT " != %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct)); 8483 } 8484 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8485 for (cl = 0; cl < closureSize*2; cl += 2) { 8486 const PetscInt p = closure[cl]; 8487 if ((p >= vStart) && (p < vEnd)) ++Nv; 8488 } 8489 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8490 /* Special Case: Tensor faces with identified vertices */ 8491 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8492 PetscInt unsplit; 8493 8494 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8495 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8496 } 8497 PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices != %" PetscInt_FMT, c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct)); 8498 } 8499 PetscFunctionReturn(0); 8500 } 8501 8502 /*@ 8503 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8504 8505 Collective 8506 8507 Input Parameters: 8508 + dm - The DMPlex object 8509 - cellHeight - Normally 0 8510 8511 Notes: 8512 This is a useful diagnostic when creating meshes programmatically. 8513 This routine is only relevant for meshes that are fully interpolated across all ranks. 8514 It will error out if a partially interpolated mesh is given on some rank. 8515 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8516 8517 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8518 8519 Level: developer 8520 8521 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8522 @*/ 8523 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8524 { 8525 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8526 DMPlexInterpolatedFlag interpEnum; 8527 8528 PetscFunctionBegin; 8529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8530 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8531 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8532 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8533 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8534 PetscFunctionReturn(0); 8535 } 8536 8537 PetscCall(DMGetDimension(dm, &dim)); 8538 PetscCall(DMPlexGetDepth(dm, &depth)); 8539 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8540 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8541 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8542 for (c = cStart; c < cEnd; ++c) { 8543 const PetscInt *cone, *ornt, *faceSizes, *faces; 8544 const DMPolytopeType *faceTypes; 8545 DMPolytopeType ct; 8546 PetscInt numFaces, coneSize, f; 8547 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8548 8549 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8550 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8551 if (unsplit) continue; 8552 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8553 PetscCall(DMPlexGetCone(dm, c, &cone)); 8554 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8555 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8556 for (cl = 0; cl < closureSize*2; cl += 2) { 8557 const PetscInt p = closure[cl]; 8558 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8559 } 8560 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8561 PetscCheck(coneSize == numFaces,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " faces but should have %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, numFaces); 8562 for (f = 0; f < numFaces; ++f) { 8563 DMPolytopeType fct; 8564 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8565 8566 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8567 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8568 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8569 const PetscInt p = fclosure[cl]; 8570 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8571 } 8572 PetscCheck(fnumCorners == faceSizes[f],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices but should have %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]); 8573 for (v = 0; v < fnumCorners; ++v) { 8574 if (fclosure[v] != faces[fOff+v]) { 8575 PetscInt v1; 8576 8577 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8578 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8579 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8580 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8581 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8582 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ", ornt %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s vertex %" PetscInt_FMT ", %" PetscInt_FMT " != %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff+v]); 8583 } 8584 } 8585 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8586 fOff += faceSizes[f]; 8587 } 8588 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8589 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8590 } 8591 } 8592 PetscFunctionReturn(0); 8593 } 8594 8595 /*@ 8596 DMPlexCheckGeometry - Check the geometry of mesh cells 8597 8598 Input Parameter: 8599 . dm - The DMPlex object 8600 8601 Notes: 8602 This is a useful diagnostic when creating meshes programmatically. 8603 8604 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8605 8606 Level: developer 8607 8608 .seealso: `DMCreate()`, `DMSetFromOptions()` 8609 @*/ 8610 PetscErrorCode DMPlexCheckGeometry(DM dm) 8611 { 8612 Vec coordinates; 8613 PetscReal detJ, J[9], refVol = 1.0; 8614 PetscReal vol; 8615 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8616 8617 PetscFunctionBegin; 8618 PetscCall(DMGetDimension(dm, &dim)); 8619 PetscCall(DMGetCoordinateDim(dm, &dE)); 8620 if (dim != dE) PetscFunctionReturn(0); 8621 PetscCall(DMPlexGetDepth(dm, &depth)); 8622 for (d = 0; d < dim; ++d) refVol *= 2.0; 8623 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8624 /* Make sure local coordinates are created, because that step is collective */ 8625 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8626 for (c = cStart; c < cEnd; ++c) { 8627 DMPolytopeType ct; 8628 PetscInt unsplit; 8629 PetscBool ignoreZeroVol = PETSC_FALSE; 8630 8631 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8632 switch (ct) { 8633 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8634 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8635 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8636 ignoreZeroVol = PETSC_TRUE; break; 8637 default: break; 8638 } 8639 switch (ct) { 8640 case DM_POLYTOPE_TRI_PRISM: 8641 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8642 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8643 case DM_POLYTOPE_PYRAMID: 8644 continue; 8645 default: break; 8646 } 8647 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8648 if (unsplit) continue; 8649 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8650 PetscCheck(detJ >= -PETSC_SMALL && (detJ > 0.0 || ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double) detJ); 8651 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8652 /* This should work with periodicity since DG coordinates should be used */ 8653 if (depth > 1) { 8654 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8655 PetscCheck(vol >= -PETSC_SMALL && (vol > 0.0 || ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double) vol); 8656 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8657 } 8658 } 8659 PetscFunctionReturn(0); 8660 } 8661 8662 /*@ 8663 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8664 8665 Collective 8666 8667 Input Parameters: 8668 + dm - The DMPlex object 8669 - pointSF - The Point SF, or NULL for Point SF attached to DM 8670 8671 Notes: 8672 This is mainly intended for debugging/testing purposes. 8673 8674 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8675 8676 Level: developer 8677 8678 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8679 @*/ 8680 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8681 { 8682 PetscInt l, nleaves, nroots, overlap; 8683 const PetscInt *locals; 8684 const PetscSFNode *remotes; 8685 PetscBool distributed; 8686 MPI_Comm comm; 8687 PetscMPIInt rank; 8688 8689 PetscFunctionBegin; 8690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8691 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8692 else pointSF = dm->sf; 8693 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8694 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8695 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8696 { 8697 PetscMPIInt mpiFlag; 8698 8699 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8700 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8701 } 8702 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8703 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8704 if (!distributed) { 8705 PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8706 PetscFunctionReturn(0); 8707 } 8708 PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8709 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8710 8711 /* Check SF graph is compatible with DMPlex chart */ 8712 { 8713 PetscInt pStart, pEnd, maxLeaf; 8714 8715 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8716 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8717 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8718 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8719 } 8720 8721 /* Check Point SF has no local points referenced */ 8722 for (l = 0; l < nleaves; l++) { 8723 PetscAssert(remotes[l].rank != (PetscInt) rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 8724 } 8725 8726 /* Check there are no cells in interface */ 8727 if (!overlap) { 8728 PetscInt cellHeight, cStart, cEnd; 8729 8730 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8731 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8732 for (l = 0; l < nleaves; ++l) { 8733 const PetscInt point = locals ? locals[l] : l; 8734 8735 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8736 } 8737 } 8738 8739 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8740 { 8741 const PetscInt *rootdegree; 8742 8743 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8744 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8745 for (l = 0; l < nleaves; ++l) { 8746 const PetscInt point = locals ? locals[l] : l; 8747 const PetscInt *cone; 8748 PetscInt coneSize, c, idx; 8749 8750 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8751 PetscCall(DMPlexGetCone(dm, point, &cone)); 8752 for (c = 0; c < coneSize; ++c) { 8753 if (!rootdegree[cone[c]]) { 8754 if (locals) { 8755 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8756 } else { 8757 idx = (cone[c] < nleaves) ? cone[c] : -1; 8758 } 8759 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8760 } 8761 } 8762 } 8763 } 8764 PetscFunctionReturn(0); 8765 } 8766 8767 /*@ 8768 DMPlexCheck - Perform various checks of Plex sanity 8769 8770 Input Parameter: 8771 . dm - The DMPlex object 8772 8773 Notes: 8774 This is a useful diagnostic when creating meshes programmatically. 8775 8776 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8777 8778 Currently does not include DMPlexCheckCellShape(). 8779 8780 Level: developer 8781 8782 .seealso: DMCreate(), DMSetFromOptions() 8783 @*/ 8784 PetscErrorCode DMPlexCheck(DM dm) 8785 { 8786 PetscInt cellHeight; 8787 8788 PetscFunctionBegin; 8789 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8790 PetscCall(DMPlexCheckSymmetry(dm)); 8791 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8792 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8793 PetscCall(DMPlexCheckGeometry(dm)); 8794 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8795 PetscCall(DMPlexCheckInterfaceCones(dm)); 8796 PetscFunctionReturn(0); 8797 } 8798 8799 typedef struct cell_stats 8800 { 8801 PetscReal min, max, sum, squaresum; 8802 PetscInt count; 8803 } cell_stats_t; 8804 8805 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8806 { 8807 PetscInt i, N = *len; 8808 8809 for (i = 0; i < N; i++) { 8810 cell_stats_t *A = (cell_stats_t *) a; 8811 cell_stats_t *B = (cell_stats_t *) b; 8812 8813 B->min = PetscMin(A->min,B->min); 8814 B->max = PetscMax(A->max,B->max); 8815 B->sum += A->sum; 8816 B->squaresum += A->squaresum; 8817 B->count += A->count; 8818 } 8819 } 8820 8821 /*@ 8822 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8823 8824 Collective on dm 8825 8826 Input Parameters: 8827 + dm - The DMPlex object 8828 . output - If true, statistics will be displayed on stdout 8829 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8830 8831 Notes: 8832 This is mainly intended for debugging/testing purposes. 8833 8834 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8835 8836 Level: developer 8837 8838 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8839 @*/ 8840 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8841 { 8842 DM dmCoarse; 8843 cell_stats_t stats, globalStats; 8844 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8845 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8846 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8847 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8848 PetscMPIInt rank,size; 8849 8850 PetscFunctionBegin; 8851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8852 stats.min = PETSC_MAX_REAL; 8853 stats.max = PETSC_MIN_REAL; 8854 stats.sum = stats.squaresum = 0.; 8855 stats.count = 0; 8856 8857 PetscCallMPI(MPI_Comm_size(comm, &size)); 8858 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8859 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8860 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8861 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8862 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8863 for (c = cStart; c < cEnd; c++) { 8864 PetscInt i; 8865 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8866 8867 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8868 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8869 for (i = 0; i < PetscSqr(cdim); ++i) { 8870 frobJ += J[i] * J[i]; 8871 frobInvJ += invJ[i] * invJ[i]; 8872 } 8873 cond2 = frobJ * frobInvJ; 8874 cond = PetscSqrtReal(cond2); 8875 8876 stats.min = PetscMin(stats.min,cond); 8877 stats.max = PetscMax(stats.max,cond); 8878 stats.sum += cond; 8879 stats.squaresum += cond2; 8880 stats.count++; 8881 if (output && cond > limit) { 8882 PetscSection coordSection; 8883 Vec coordsLocal; 8884 PetscScalar *coords = NULL; 8885 PetscInt Nv, d, clSize, cl, *closure = NULL; 8886 8887 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8888 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8889 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8890 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8891 for (i = 0; i < Nv/cdim; ++i) { 8892 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8893 for (d = 0; d < cdim; ++d) { 8894 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8895 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8896 } 8897 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8898 } 8899 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8900 for (cl = 0; cl < clSize*2; cl += 2) { 8901 const PetscInt edge = closure[cl]; 8902 8903 if ((edge >= eStart) && (edge < eEnd)) { 8904 PetscReal len; 8905 8906 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8907 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8908 } 8909 } 8910 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8911 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8912 } 8913 } 8914 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8915 8916 if (size > 1) { 8917 PetscMPIInt blockLengths[2] = {4,1}; 8918 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8919 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8920 MPI_Op statReduce; 8921 8922 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8923 PetscCallMPI(MPI_Type_commit(&statType)); 8924 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8925 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8926 PetscCallMPI(MPI_Op_free(&statReduce)); 8927 PetscCallMPI(MPI_Type_free(&statType)); 8928 } else { 8929 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8930 } 8931 if (rank == 0) { 8932 count = globalStats.count; 8933 min = globalStats.min; 8934 max = globalStats.max; 8935 mean = globalStats.sum / globalStats.count; 8936 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8937 } 8938 8939 if (output) { 8940 PetscCall(PetscPrintf(comm,"Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev)); 8941 } 8942 PetscCall(PetscFree2(J,invJ)); 8943 8944 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8945 if (dmCoarse) { 8946 PetscBool isplex; 8947 8948 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8949 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8950 } 8951 PetscFunctionReturn(0); 8952 } 8953 8954 /*@ 8955 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8956 orthogonal quality below given tolerance. 8957 8958 Collective on dm 8959 8960 Input Parameters: 8961 + dm - The DMPlex object 8962 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8963 - atol - [0, 1] Absolute tolerance for tagging cells. 8964 8965 Output Parameters: 8966 + OrthQual - Vec containing orthogonal quality per cell 8967 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8968 8969 Options Database Keys: 8970 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8971 supported. 8972 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8973 8974 Notes: 8975 Orthogonal quality is given by the following formula: 8976 8977 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8978 8979 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 8980 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8981 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8982 calculating the cosine of the angle between these vectors. 8983 8984 Orthogonal quality ranges from 1 (best) to 0 (worst). 8985 8986 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8987 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8988 8989 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8990 8991 Level: intermediate 8992 8993 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8994 @*/ 8995 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8996 { 8997 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8998 PetscInt *idx; 8999 PetscScalar *oqVals; 9000 const PetscScalar *cellGeomArr, *faceGeomArr; 9001 PetscReal *ci, *fi, *Ai; 9002 MPI_Comm comm; 9003 Vec cellgeom, facegeom; 9004 DM dmFace, dmCell; 9005 IS glob; 9006 ISLocalToGlobalMapping ltog; 9007 PetscViewer vwr; 9008 9009 PetscFunctionBegin; 9010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9011 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 9012 PetscValidPointer(OrthQual, 4); 9013 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 9014 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9015 PetscCall(DMGetDimension(dm, &nc)); 9016 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9017 { 9018 DMPlexInterpolatedFlag interpFlag; 9019 9020 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9021 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9022 PetscMPIInt rank; 9023 9024 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9025 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9026 } 9027 } 9028 if (OrthQualLabel) { 9029 PetscValidPointer(OrthQualLabel, 5); 9030 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9031 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9032 } else {*OrthQualLabel = NULL;} 9033 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9034 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9035 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9036 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9037 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9038 PetscCall(VecCreate(comm, OrthQual)); 9039 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9040 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9041 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9042 PetscCall(VecSetUp(*OrthQual)); 9043 PetscCall(ISDestroy(&glob)); 9044 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9045 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9046 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9047 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9048 PetscCall(VecGetDM(cellgeom, &dmCell)); 9049 PetscCall(VecGetDM(facegeom, &dmFace)); 9050 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9051 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9052 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9053 PetscInt cellarr[2], *adj = NULL; 9054 PetscScalar *cArr, *fArr; 9055 PetscReal minvalc = 1.0, minvalf = 1.0; 9056 PetscFVCellGeom *cg; 9057 9058 idx[cellIter] = cell-cStart; 9059 cellarr[0] = cell; 9060 /* Make indexing into cellGeom easier */ 9061 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9062 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9063 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9064 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9065 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9066 PetscInt i; 9067 const PetscInt neigh = adj[cellneigh]; 9068 PetscReal normci = 0, normfi = 0, normai = 0; 9069 PetscFVCellGeom *cgneigh; 9070 PetscFVFaceGeom *fg; 9071 9072 /* Don't count ourselves in the neighbor list */ 9073 if (neigh == cell) continue; 9074 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9075 cellarr[1] = neigh; 9076 { 9077 PetscInt numcovpts; 9078 const PetscInt *covpts; 9079 9080 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9081 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9082 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9083 } 9084 9085 /* Compute c_i, f_i and their norms */ 9086 for (i = 0; i < nc; i++) { 9087 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9088 fi[i] = fg->centroid[i] - cg->centroid[i]; 9089 Ai[i] = fg->normal[i]; 9090 normci += PetscPowReal(ci[i], 2); 9091 normfi += PetscPowReal(fi[i], 2); 9092 normai += PetscPowReal(Ai[i], 2); 9093 } 9094 normci = PetscSqrtReal(normci); 9095 normfi = PetscSqrtReal(normfi); 9096 normai = PetscSqrtReal(normai); 9097 9098 /* Normalize and compute for each face-cell-normal pair */ 9099 for (i = 0; i < nc; i++) { 9100 ci[i] = ci[i]/normci; 9101 fi[i] = fi[i]/normfi; 9102 Ai[i] = Ai[i]/normai; 9103 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9104 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9105 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9106 } 9107 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9108 minvalc = PetscRealPart(cArr[cellneighiter]); 9109 } 9110 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9111 minvalf = PetscRealPart(fArr[cellneighiter]); 9112 } 9113 } 9114 PetscCall(PetscFree(adj)); 9115 PetscCall(PetscFree2(cArr, fArr)); 9116 /* Defer to cell if they're equal */ 9117 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9118 if (OrthQualLabel) { 9119 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9120 } 9121 } 9122 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9123 PetscCall(VecAssemblyBegin(*OrthQual)); 9124 PetscCall(VecAssemblyEnd(*OrthQual)); 9125 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9126 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9127 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9128 if (OrthQualLabel) { 9129 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9130 } 9131 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9132 PetscCall(PetscViewerDestroy(&vwr)); 9133 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9134 PetscFunctionReturn(0); 9135 } 9136 9137 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9138 * interpolator construction */ 9139 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9140 { 9141 PetscSection section, newSection, gsection; 9142 PetscSF sf; 9143 PetscBool hasConstraints, ghasConstraints; 9144 9145 PetscFunctionBegin; 9146 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9147 PetscValidPointer(odm,2); 9148 PetscCall(DMGetLocalSection(dm, §ion)); 9149 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9150 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9151 if (!ghasConstraints) { 9152 PetscCall(PetscObjectReference((PetscObject)dm)); 9153 *odm = dm; 9154 PetscFunctionReturn(0); 9155 } 9156 PetscCall(DMClone(dm, odm)); 9157 PetscCall(DMCopyFields(dm, *odm)); 9158 PetscCall(DMGetLocalSection(*odm, &newSection)); 9159 PetscCall(DMGetPointSF(*odm, &sf)); 9160 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9161 PetscCall(DMSetGlobalSection(*odm, gsection)); 9162 PetscCall(PetscSectionDestroy(&gsection)); 9163 PetscFunctionReturn(0); 9164 } 9165 9166 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9167 { 9168 DM dmco, dmfo; 9169 Mat interpo; 9170 Vec rscale; 9171 Vec cglobalo, clocal; 9172 Vec fglobal, fglobalo, flocal; 9173 PetscBool regular; 9174 9175 PetscFunctionBegin; 9176 PetscCall(DMGetFullDM(dmc, &dmco)); 9177 PetscCall(DMGetFullDM(dmf, &dmfo)); 9178 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9179 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9180 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9181 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9182 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9183 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9184 PetscCall(VecSet(cglobalo, 0.)); 9185 PetscCall(VecSet(clocal, 0.)); 9186 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9187 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9188 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9189 PetscCall(VecSet(fglobal, 0.)); 9190 PetscCall(VecSet(fglobalo, 0.)); 9191 PetscCall(VecSet(flocal, 0.)); 9192 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9193 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9194 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9195 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9196 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9197 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9198 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9199 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9200 *shift = fglobal; 9201 PetscCall(VecDestroy(&flocal)); 9202 PetscCall(VecDestroy(&fglobalo)); 9203 PetscCall(VecDestroy(&clocal)); 9204 PetscCall(VecDestroy(&cglobalo)); 9205 PetscCall(VecDestroy(&rscale)); 9206 PetscCall(MatDestroy(&interpo)); 9207 PetscCall(DMDestroy(&dmfo)); 9208 PetscCall(DMDestroy(&dmco)); 9209 PetscFunctionReturn(0); 9210 } 9211 9212 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9213 { 9214 PetscObject shifto; 9215 Vec shift; 9216 9217 PetscFunctionBegin; 9218 if (!interp) { 9219 Vec rscale; 9220 9221 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9222 PetscCall(VecDestroy(&rscale)); 9223 } else { 9224 PetscCall(PetscObjectReference((PetscObject)interp)); 9225 } 9226 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9227 if (!shifto) { 9228 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9229 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9230 shifto = (PetscObject) shift; 9231 PetscCall(VecDestroy(&shift)); 9232 } 9233 shift = (Vec) shifto; 9234 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9235 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9236 PetscCall(MatDestroy(&interp)); 9237 PetscFunctionReturn(0); 9238 } 9239 9240 /* Pointwise interpolation 9241 Just code FEM for now 9242 u^f = I u^c 9243 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9244 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9245 I_{ij} = psi^f_i phi^c_j 9246 */ 9247 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9248 { 9249 PetscSection gsc, gsf; 9250 PetscInt m, n; 9251 void *ctx; 9252 DM cdm; 9253 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9254 9255 PetscFunctionBegin; 9256 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9257 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9258 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9259 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9260 9261 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9262 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9263 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9264 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9265 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9266 9267 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9268 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9269 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9270 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9271 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9272 if (scaling) { 9273 /* Use naive scaling */ 9274 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9275 } 9276 PetscFunctionReturn(0); 9277 } 9278 9279 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9280 { 9281 VecScatter ctx; 9282 9283 PetscFunctionBegin; 9284 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9285 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9286 PetscCall(VecScatterDestroy(&ctx)); 9287 PetscFunctionReturn(0); 9288 } 9289 9290 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9291 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9292 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9293 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9294 { 9295 const PetscInt Nc = uOff[1] - uOff[0]; 9296 PetscInt c; 9297 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9298 } 9299 9300 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9301 { 9302 DM dmc; 9303 PetscDS ds; 9304 Vec ones, locmass; 9305 IS cellIS; 9306 PetscFormKey key; 9307 PetscInt depth; 9308 9309 PetscFunctionBegin; 9310 PetscCall(DMClone(dm, &dmc)); 9311 PetscCall(DMCopyDisc(dm, dmc)); 9312 PetscCall(DMGetDS(dmc, &ds)); 9313 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9314 PetscCall(DMCreateGlobalVector(dmc, mass)); 9315 PetscCall(DMGetLocalVector(dmc, &ones)); 9316 PetscCall(DMGetLocalVector(dmc, &locmass)); 9317 PetscCall(DMPlexGetDepth(dmc, &depth)); 9318 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9319 PetscCall(VecSet(locmass, 0.0)); 9320 PetscCall(VecSet(ones, 1.0)); 9321 key.label = NULL; 9322 key.value = 0; 9323 key.field = 0; 9324 key.part = 0; 9325 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9326 PetscCall(ISDestroy(&cellIS)); 9327 PetscCall(VecSet(*mass, 0.0)); 9328 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9329 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9330 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9331 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9332 PetscCall(DMDestroy(&dmc)); 9333 PetscFunctionReturn(0); 9334 } 9335 9336 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9337 { 9338 PetscSection gsc, gsf; 9339 PetscInt m, n; 9340 void *ctx; 9341 DM cdm; 9342 PetscBool regular; 9343 9344 PetscFunctionBegin; 9345 if (dmFine == dmCoarse) { 9346 DM dmc; 9347 PetscDS ds; 9348 PetscWeakForm wf; 9349 Vec u; 9350 IS cellIS; 9351 PetscFormKey key; 9352 PetscInt depth; 9353 9354 PetscCall(DMClone(dmFine, &dmc)); 9355 PetscCall(DMCopyDisc(dmFine, dmc)); 9356 PetscCall(DMGetDS(dmc, &ds)); 9357 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9358 PetscCall(PetscWeakFormClear(wf)); 9359 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9360 PetscCall(DMCreateMatrix(dmc, mass)); 9361 PetscCall(DMGetLocalVector(dmc, &u)); 9362 PetscCall(DMPlexGetDepth(dmc, &depth)); 9363 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9364 PetscCall(MatZeroEntries(*mass)); 9365 key.label = NULL; 9366 key.value = 0; 9367 key.field = 0; 9368 key.part = 0; 9369 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9370 PetscCall(ISDestroy(&cellIS)); 9371 PetscCall(DMRestoreLocalVector(dmc, &u)); 9372 PetscCall(DMDestroy(&dmc)); 9373 } else { 9374 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9375 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9376 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9377 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9378 9379 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9380 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9381 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9382 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9383 9384 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9385 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9386 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9387 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9388 } 9389 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9390 PetscFunctionReturn(0); 9391 } 9392 9393 /*@ 9394 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9395 9396 Input Parameter: 9397 . dm - The DMPlex object 9398 9399 Output Parameter: 9400 . regular - The flag 9401 9402 Level: intermediate 9403 9404 .seealso: `DMPlexSetRegularRefinement()` 9405 @*/ 9406 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9407 { 9408 PetscFunctionBegin; 9409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9410 PetscValidBoolPointer(regular, 2); 9411 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9412 PetscFunctionReturn(0); 9413 } 9414 9415 /*@ 9416 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9417 9418 Input Parameters: 9419 + dm - The DMPlex object 9420 - regular - The flag 9421 9422 Level: intermediate 9423 9424 .seealso: `DMPlexGetRegularRefinement()` 9425 @*/ 9426 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9427 { 9428 PetscFunctionBegin; 9429 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9430 ((DM_Plex *) dm->data)->regularRefinement = regular; 9431 PetscFunctionReturn(0); 9432 } 9433 9434 /* anchors */ 9435 /*@ 9436 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9437 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9438 9439 not collective 9440 9441 Input Parameter: 9442 . dm - The DMPlex object 9443 9444 Output Parameters: 9445 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9446 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9447 9448 Level: intermediate 9449 9450 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9451 @*/ 9452 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9453 { 9454 DM_Plex *plex = (DM_Plex *)dm->data; 9455 9456 PetscFunctionBegin; 9457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9458 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9459 if (anchorSection) *anchorSection = plex->anchorSection; 9460 if (anchorIS) *anchorIS = plex->anchorIS; 9461 PetscFunctionReturn(0); 9462 } 9463 9464 /*@ 9465 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9466 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9467 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9468 9469 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9470 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9471 9472 collective on dm 9473 9474 Input Parameters: 9475 + dm - The DMPlex object 9476 . 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). 9477 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9478 9479 The reference counts of anchorSection and anchorIS are incremented. 9480 9481 Level: intermediate 9482 9483 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9484 @*/ 9485 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9486 { 9487 DM_Plex *plex = (DM_Plex *)dm->data; 9488 PetscMPIInt result; 9489 9490 PetscFunctionBegin; 9491 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9492 if (anchorSection) { 9493 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9494 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9495 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9496 } 9497 if (anchorIS) { 9498 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9499 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9500 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9501 } 9502 9503 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9504 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9505 plex->anchorSection = anchorSection; 9506 9507 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9508 PetscCall(ISDestroy(&plex->anchorIS)); 9509 plex->anchorIS = anchorIS; 9510 9511 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9512 PetscInt size, a, pStart, pEnd; 9513 const PetscInt *anchors; 9514 9515 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9516 PetscCall(ISGetLocalSize(anchorIS,&size)); 9517 PetscCall(ISGetIndices(anchorIS,&anchors)); 9518 for (a = 0; a < size; a++) { 9519 PetscInt p; 9520 9521 p = anchors[a]; 9522 if (p >= pStart && p < pEnd) { 9523 PetscInt dof; 9524 9525 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9526 if (dof) { 9527 9528 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9529 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9530 } 9531 } 9532 } 9533 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9534 } 9535 /* reset the generic constraints */ 9536 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9537 PetscFunctionReturn(0); 9538 } 9539 9540 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9541 { 9542 PetscSection anchorSection; 9543 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9544 9545 PetscFunctionBegin; 9546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9547 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9548 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9549 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9550 if (numFields) { 9551 PetscInt f; 9552 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9553 9554 for (f = 0; f < numFields; f++) { 9555 PetscInt numComp; 9556 9557 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9558 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9559 } 9560 } 9561 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9562 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9563 pStart = PetscMax(pStart,sStart); 9564 pEnd = PetscMin(pEnd,sEnd); 9565 pEnd = PetscMax(pStart,pEnd); 9566 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9567 for (p = pStart; p < pEnd; p++) { 9568 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9569 if (dof) { 9570 PetscCall(PetscSectionGetDof(section,p,&dof)); 9571 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9572 for (f = 0; f < numFields; f++) { 9573 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9574 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9575 } 9576 } 9577 } 9578 PetscCall(PetscSectionSetUp(*cSec)); 9579 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9580 PetscFunctionReturn(0); 9581 } 9582 9583 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9584 { 9585 PetscSection aSec; 9586 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9587 const PetscInt *anchors; 9588 PetscInt numFields, f; 9589 IS aIS; 9590 MatType mtype; 9591 PetscBool iscuda,iskokkos; 9592 9593 PetscFunctionBegin; 9594 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9595 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9596 PetscCall(PetscSectionGetStorageSize(section, &n)); 9597 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9598 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9599 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9600 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9601 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9602 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9603 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9604 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9605 else mtype = MATSEQAIJ; 9606 PetscCall(MatSetType(*cMat,mtype)); 9607 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9608 PetscCall(ISGetIndices(aIS,&anchors)); 9609 /* cSec will be a subset of aSec and section */ 9610 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9611 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9612 PetscCall(PetscMalloc1(m+1,&i)); 9613 i[0] = 0; 9614 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9615 for (p = pStart; p < pEnd; p++) { 9616 PetscInt rDof, rOff, r; 9617 9618 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9619 if (!rDof) continue; 9620 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9621 if (numFields) { 9622 for (f = 0; f < numFields; f++) { 9623 annz = 0; 9624 for (r = 0; r < rDof; r++) { 9625 a = anchors[rOff + r]; 9626 if (a < sStart || a >= sEnd) continue; 9627 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9628 annz += aDof; 9629 } 9630 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9631 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9632 for (q = 0; q < dof; q++) { 9633 i[off + q + 1] = i[off + q] + annz; 9634 } 9635 } 9636 } else { 9637 annz = 0; 9638 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9639 for (q = 0; q < dof; q++) { 9640 a = anchors[rOff + q]; 9641 if (a < sStart || a >= sEnd) continue; 9642 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9643 annz += aDof; 9644 } 9645 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9646 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9647 for (q = 0; q < dof; q++) { 9648 i[off + q + 1] = i[off + q] + annz; 9649 } 9650 } 9651 } 9652 nnz = i[m]; 9653 PetscCall(PetscMalloc1(nnz,&j)); 9654 offset = 0; 9655 for (p = pStart; p < pEnd; p++) { 9656 if (numFields) { 9657 for (f = 0; f < numFields; f++) { 9658 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9659 for (q = 0; q < dof; q++) { 9660 PetscInt rDof, rOff, r; 9661 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9662 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9663 for (r = 0; r < rDof; r++) { 9664 PetscInt s; 9665 9666 a = anchors[rOff + r]; 9667 if (a < sStart || a >= sEnd) continue; 9668 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9669 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9670 for (s = 0; s < aDof; s++) { 9671 j[offset++] = aOff + s; 9672 } 9673 } 9674 } 9675 } 9676 } else { 9677 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9678 for (q = 0; q < dof; q++) { 9679 PetscInt rDof, rOff, r; 9680 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9681 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9682 for (r = 0; r < rDof; r++) { 9683 PetscInt s; 9684 9685 a = anchors[rOff + r]; 9686 if (a < sStart || a >= sEnd) continue; 9687 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9688 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9689 for (s = 0; s < aDof; s++) { 9690 j[offset++] = aOff + s; 9691 } 9692 } 9693 } 9694 } 9695 } 9696 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9697 PetscCall(PetscFree(i)); 9698 PetscCall(PetscFree(j)); 9699 PetscCall(ISRestoreIndices(aIS,&anchors)); 9700 PetscFunctionReturn(0); 9701 } 9702 9703 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9704 { 9705 DM_Plex *plex = (DM_Plex *)dm->data; 9706 PetscSection anchorSection, section, cSec; 9707 Mat cMat; 9708 9709 PetscFunctionBegin; 9710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9711 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9712 if (anchorSection) { 9713 PetscInt Nf; 9714 9715 PetscCall(DMGetLocalSection(dm,§ion)); 9716 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9717 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9718 PetscCall(DMGetNumFields(dm,&Nf)); 9719 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9720 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9721 PetscCall(PetscSectionDestroy(&cSec)); 9722 PetscCall(MatDestroy(&cMat)); 9723 } 9724 PetscFunctionReturn(0); 9725 } 9726 9727 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9728 { 9729 IS subis; 9730 PetscSection section, subsection; 9731 9732 PetscFunctionBegin; 9733 PetscCall(DMGetLocalSection(dm, §ion)); 9734 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9735 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9736 /* Create subdomain */ 9737 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9738 /* Create submodel */ 9739 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9740 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9741 PetscCall(DMSetLocalSection(*subdm, subsection)); 9742 PetscCall(PetscSectionDestroy(&subsection)); 9743 PetscCall(DMCopyDisc(dm, *subdm)); 9744 /* Create map from submodel to global model */ 9745 if (is) { 9746 PetscSection sectionGlobal, subsectionGlobal; 9747 IS spIS; 9748 const PetscInt *spmap; 9749 PetscInt *subIndices; 9750 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9751 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9752 9753 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9754 PetscCall(ISGetIndices(spIS, &spmap)); 9755 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9756 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9757 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9758 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9759 for (p = pStart; p < pEnd; ++p) { 9760 PetscInt gdof, pSubSize = 0; 9761 9762 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9763 if (gdof > 0) { 9764 for (f = 0; f < Nf; ++f) { 9765 PetscInt fdof, fcdof; 9766 9767 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9768 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9769 pSubSize += fdof-fcdof; 9770 } 9771 subSize += pSubSize; 9772 if (pSubSize) { 9773 if (bs < 0) { 9774 bs = pSubSize; 9775 } else if (bs != pSubSize) { 9776 /* Layout does not admit a pointwise block size */ 9777 bs = 1; 9778 } 9779 } 9780 } 9781 } 9782 /* Must have same blocksize on all procs (some might have no points) */ 9783 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9784 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9785 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9786 else {bs = bsMinMax[0];} 9787 PetscCall(PetscMalloc1(subSize, &subIndices)); 9788 for (p = pStart; p < pEnd; ++p) { 9789 PetscInt gdof, goff; 9790 9791 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9792 if (gdof > 0) { 9793 const PetscInt point = spmap[p]; 9794 9795 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9796 for (f = 0; f < Nf; ++f) { 9797 PetscInt fdof, fcdof, fc, f2, poff = 0; 9798 9799 /* Can get rid of this loop by storing field information in the global section */ 9800 for (f2 = 0; f2 < f; ++f2) { 9801 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9802 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9803 poff += fdof-fcdof; 9804 } 9805 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9806 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9807 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9808 subIndices[subOff] = goff+poff+fc; 9809 } 9810 } 9811 } 9812 } 9813 PetscCall(ISRestoreIndices(spIS, &spmap)); 9814 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9815 if (bs > 1) { 9816 /* We need to check that the block size does not come from non-contiguous fields */ 9817 PetscInt i, j, set = 1; 9818 for (i = 0; i < subSize; i += bs) { 9819 for (j = 0; j < bs; ++j) { 9820 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9821 } 9822 } 9823 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9824 } 9825 /* Attach nullspace */ 9826 for (f = 0; f < Nf; ++f) { 9827 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9828 if ((*subdm)->nullspaceConstructors[f]) break; 9829 } 9830 if (f < Nf) { 9831 MatNullSpace nullSpace; 9832 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9833 9834 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9835 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9836 } 9837 } 9838 PetscFunctionReturn(0); 9839 } 9840 9841 /*@ 9842 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9843 9844 Input Parameter: 9845 - dm - The DM 9846 9847 Level: developer 9848 9849 Options Database Keys: 9850 . -dm_plex_monitor_throughput - Activate the monitor 9851 9852 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9853 @*/ 9854 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9855 { 9856 #if defined(PETSC_USE_LOG) 9857 PetscStageLog stageLog; 9858 PetscLogEvent event; 9859 PetscLogStage stage; 9860 PetscEventPerfInfo eventInfo; 9861 PetscReal cellRate, flopRate; 9862 PetscInt cStart, cEnd, Nf, N; 9863 const char *name; 9864 #endif 9865 9866 PetscFunctionBegin; 9867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9868 #if defined(PETSC_USE_LOG) 9869 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9870 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9871 PetscCall(DMGetNumFields(dm, &Nf)); 9872 PetscCall(PetscLogGetStageLog(&stageLog)); 9873 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9874 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9875 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9876 N = (cEnd - cStart)*Nf*eventInfo.count; 9877 flopRate = eventInfo.flops/eventInfo.time; 9878 cellRate = N/eventInfo.time; 9879 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " 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))); 9880 #else 9881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9882 #endif 9883 PetscFunctionReturn(0); 9884 } 9885