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 Notes: 3669 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3670 3671 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3672 3673 Level: beginner 3674 3675 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3676 @*/ 3677 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3678 { 3679 PetscFunctionBeginHot; 3680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3681 if (numPoints) PetscValidIntPointer(numPoints, 4); 3682 if (points) PetscValidPointer(points, 5); 3683 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3684 PetscFunctionReturn(0); 3685 } 3686 3687 /*@C 3688 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3689 3690 Not collective 3691 3692 Input Parameters: 3693 + dm - The DMPlex 3694 . p - The mesh point 3695 . useCone - PETSC_TRUE for the closure, otherwise return the star 3696 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3697 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3698 3699 Note: 3700 If not using internal storage (points is not NULL on input), this call is unnecessary 3701 3702 Fortran Notes: 3703 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3704 3705 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3706 3707 Level: beginner 3708 3709 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3710 @*/ 3711 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3712 { 3713 PetscFunctionBeginHot; 3714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3715 if (numPoints) *numPoints = 0; 3716 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3717 PetscFunctionReturn(0); 3718 } 3719 3720 /*@ 3721 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3722 3723 Not collective 3724 3725 Input Parameter: 3726 . mesh - The DMPlex 3727 3728 Output Parameters: 3729 + maxConeSize - The maximum number of in-edges 3730 - maxSupportSize - The maximum number of out-edges 3731 3732 Level: beginner 3733 3734 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3735 @*/ 3736 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3737 { 3738 DM_Plex *mesh = (DM_Plex*) dm->data; 3739 3740 PetscFunctionBegin; 3741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3742 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3743 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3744 PetscFunctionReturn(0); 3745 } 3746 3747 PetscErrorCode DMSetUp_Plex(DM dm) 3748 { 3749 DM_Plex *mesh = (DM_Plex*) dm->data; 3750 PetscInt size, maxSupportSize; 3751 3752 PetscFunctionBegin; 3753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3754 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3755 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3756 PetscCall(PetscMalloc1(size, &mesh->cones)); 3757 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3758 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3759 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3760 if (maxSupportSize) { 3761 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3762 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3763 PetscCall(PetscMalloc1(size, &mesh->supports)); 3764 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3765 } 3766 PetscFunctionReturn(0); 3767 } 3768 3769 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3770 { 3771 PetscFunctionBegin; 3772 if (subdm) PetscCall(DMClone(dm, subdm)); 3773 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3774 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3775 if (dm->useNatural && dm->sfMigration) { 3776 PetscSF sfMigrationInv,sfNatural; 3777 PetscSection section, sectionSeq; 3778 3779 (*subdm)->sfMigration = dm->sfMigration; 3780 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3781 PetscCall(DMGetLocalSection((*subdm), §ion)); 3782 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3783 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3784 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3785 3786 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3787 (*subdm)->sfNatural = sfNatural; 3788 PetscCall(PetscSectionDestroy(§ionSeq)); 3789 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3790 } 3791 PetscFunctionReturn(0); 3792 } 3793 3794 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3795 { 3796 PetscInt i = 0; 3797 3798 PetscFunctionBegin; 3799 PetscCall(DMClone(dms[0], superdm)); 3800 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3801 (*superdm)->useNatural = PETSC_FALSE; 3802 for (i = 0; i < len; i++) { 3803 if (dms[i]->useNatural && dms[i]->sfMigration) { 3804 PetscSF sfMigrationInv,sfNatural; 3805 PetscSection section, sectionSeq; 3806 3807 (*superdm)->sfMigration = dms[i]->sfMigration; 3808 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3809 (*superdm)->useNatural = PETSC_TRUE; 3810 PetscCall(DMGetLocalSection((*superdm), §ion)); 3811 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3812 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3813 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3814 3815 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3816 (*superdm)->sfNatural = sfNatural; 3817 PetscCall(PetscSectionDestroy(§ionSeq)); 3818 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3819 break; 3820 } 3821 } 3822 PetscFunctionReturn(0); 3823 } 3824 3825 /*@ 3826 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3827 3828 Not collective 3829 3830 Input Parameter: 3831 . mesh - The DMPlex 3832 3833 Output Parameter: 3834 3835 Note: 3836 This should be called after all calls to DMPlexSetCone() 3837 3838 Level: beginner 3839 3840 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3841 @*/ 3842 PetscErrorCode DMPlexSymmetrize(DM dm) 3843 { 3844 DM_Plex *mesh = (DM_Plex*) dm->data; 3845 PetscInt *offsets; 3846 PetscInt supportSize; 3847 PetscInt pStart, pEnd, p; 3848 3849 PetscFunctionBegin; 3850 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3851 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3852 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3853 /* Calculate support sizes */ 3854 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3855 for (p = pStart; p < pEnd; ++p) { 3856 PetscInt dof, off, c; 3857 3858 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3859 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3860 for (c = off; c < off+dof; ++c) { 3861 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3862 } 3863 } 3864 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3865 /* Calculate supports */ 3866 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3867 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3868 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3869 for (p = pStart; p < pEnd; ++p) { 3870 PetscInt dof, off, c; 3871 3872 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3873 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3874 for (c = off; c < off+dof; ++c) { 3875 const PetscInt q = mesh->cones[c]; 3876 PetscInt offS; 3877 3878 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3879 3880 mesh->supports[offS+offsets[q]] = p; 3881 ++offsets[q]; 3882 } 3883 } 3884 PetscCall(PetscFree(offsets)); 3885 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3886 PetscFunctionReturn(0); 3887 } 3888 3889 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3890 { 3891 IS stratumIS; 3892 3893 PetscFunctionBegin; 3894 if (pStart >= pEnd) PetscFunctionReturn(0); 3895 if (PetscDefined(USE_DEBUG)) { 3896 PetscInt qStart, qEnd, numLevels, level; 3897 PetscBool overlap = PETSC_FALSE; 3898 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3899 for (level = 0; level < numLevels; level++) { 3900 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3901 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3902 } 3903 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); 3904 } 3905 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3906 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3907 PetscCall(ISDestroy(&stratumIS)); 3908 PetscFunctionReturn(0); 3909 } 3910 3911 /*@ 3912 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3913 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3914 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3915 the DAG. 3916 3917 Collective on dm 3918 3919 Input Parameter: 3920 . mesh - The DMPlex 3921 3922 Output Parameter: 3923 3924 Notes: 3925 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3926 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3927 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3928 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3929 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3930 3931 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3932 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3933 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 3934 to interpolate only that one (e0), so that 3935 $ cone(c0) = {e0, v2} 3936 $ cone(e0) = {v0, v1} 3937 If DMPlexStratify() is run on this mesh, it will give depths 3938 $ depth 0 = {v0, v1, v2} 3939 $ depth 1 = {e0, c0} 3940 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3941 3942 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3943 3944 Level: beginner 3945 3946 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3947 @*/ 3948 PetscErrorCode DMPlexStratify(DM dm) 3949 { 3950 DM_Plex *mesh = (DM_Plex*) dm->data; 3951 DMLabel label; 3952 PetscInt pStart, pEnd, p; 3953 PetscInt numRoots = 0, numLeaves = 0; 3954 3955 PetscFunctionBegin; 3956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3957 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3958 3959 /* Create depth label */ 3960 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3961 PetscCall(DMCreateLabel(dm, "depth")); 3962 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3963 3964 { 3965 /* Initialize roots and count leaves */ 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 (!coneSize && supportSize) { 3974 sMin = PetscMin(p, sMin); 3975 sMax = PetscMax(p, sMax); 3976 ++numRoots; 3977 } else if (!supportSize && coneSize) { 3978 ++numLeaves; 3979 } else if (!supportSize && !coneSize) { 3980 /* Isolated points */ 3981 sMin = PetscMin(p, sMin); 3982 sMax = PetscMax(p, sMax); 3983 } 3984 } 3985 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3986 } 3987 3988 if (numRoots + numLeaves == (pEnd - pStart)) { 3989 PetscInt sMin = PETSC_MAX_INT; 3990 PetscInt sMax = PETSC_MIN_INT; 3991 PetscInt coneSize, supportSize; 3992 3993 for (p = pStart; p < pEnd; ++p) { 3994 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3995 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3996 if (!supportSize && coneSize) { 3997 sMin = PetscMin(p, sMin); 3998 sMax = PetscMax(p, sMax); 3999 } 4000 } 4001 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 4002 } else { 4003 PetscInt level = 0; 4004 PetscInt qStart, qEnd, q; 4005 4006 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4007 while (qEnd > qStart) { 4008 PetscInt sMin = PETSC_MAX_INT; 4009 PetscInt sMax = PETSC_MIN_INT; 4010 4011 for (q = qStart; q < qEnd; ++q) { 4012 const PetscInt *support; 4013 PetscInt supportSize, s; 4014 4015 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4016 PetscCall(DMPlexGetSupport(dm, q, &support)); 4017 for (s = 0; s < supportSize; ++s) { 4018 sMin = PetscMin(support[s], sMin); 4019 sMax = PetscMax(support[s], sMax); 4020 } 4021 } 4022 PetscCall(DMLabelGetNumValues(label, &level)); 4023 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4024 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4025 } 4026 } 4027 { /* just in case there is an empty process */ 4028 PetscInt numValues, maxValues = 0, v; 4029 4030 PetscCall(DMLabelGetNumValues(label, &numValues)); 4031 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4032 for (v = numValues; v < maxValues; v++) { 4033 PetscCall(DMLabelAddStratum(label, v)); 4034 } 4035 } 4036 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4037 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4038 PetscFunctionReturn(0); 4039 } 4040 4041 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4042 { 4043 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4044 PetscInt dim, depth, pheight, coneSize; 4045 4046 PetscFunctionBeginHot; 4047 PetscCall(DMGetDimension(dm, &dim)); 4048 PetscCall(DMPlexGetDepth(dm, &depth)); 4049 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4050 pheight = depth - pdepth; 4051 if (depth <= 1) { 4052 switch (pdepth) { 4053 case 0: ct = DM_POLYTOPE_POINT;break; 4054 case 1: 4055 switch (coneSize) { 4056 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4057 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4058 case 4: 4059 switch (dim) { 4060 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4061 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4062 default: break; 4063 } 4064 break; 4065 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4066 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4067 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4068 default: break; 4069 } 4070 } 4071 } else { 4072 if (pdepth == 0) { 4073 ct = DM_POLYTOPE_POINT; 4074 } else if (pheight == 0) { 4075 switch (dim) { 4076 case 1: 4077 switch (coneSize) { 4078 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4079 default: break; 4080 } 4081 break; 4082 case 2: 4083 switch (coneSize) { 4084 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4085 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4086 default: break; 4087 } 4088 break; 4089 case 3: 4090 switch (coneSize) { 4091 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4092 case 5: 4093 { 4094 const PetscInt *cone; 4095 PetscInt faceConeSize; 4096 4097 PetscCall(DMPlexGetCone(dm, p, &cone)); 4098 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4099 switch (faceConeSize) { 4100 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4101 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4102 } 4103 } 4104 break; 4105 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4106 default: break; 4107 } 4108 break; 4109 default: break; 4110 } 4111 } else if (pheight > 0) { 4112 switch (coneSize) { 4113 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4114 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4115 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4116 default: break; 4117 } 4118 } 4119 } 4120 *pt = ct; 4121 PetscFunctionReturn(0); 4122 } 4123 4124 /*@ 4125 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4126 4127 Collective on dm 4128 4129 Input Parameter: 4130 . mesh - The DMPlex 4131 4132 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4133 4134 Level: developer 4135 4136 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4137 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4138 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4139 4140 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4141 @*/ 4142 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4143 { 4144 DM_Plex *mesh; 4145 DMLabel ctLabel; 4146 PetscInt pStart, pEnd, p; 4147 4148 PetscFunctionBegin; 4149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4150 mesh = (DM_Plex *) dm->data; 4151 PetscCall(DMCreateLabel(dm, "celltype")); 4152 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4153 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4154 for (p = pStart; p < pEnd; ++p) { 4155 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4156 PetscInt pdepth; 4157 4158 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4159 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4160 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4161 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4162 } 4163 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4164 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4165 PetscFunctionReturn(0); 4166 } 4167 4168 /*@C 4169 DMPlexGetJoin - Get an array for the join of the set of points 4170 4171 Not Collective 4172 4173 Input Parameters: 4174 + dm - The DMPlex object 4175 . numPoints - The number of input points for the join 4176 - points - The input points 4177 4178 Output Parameters: 4179 + numCoveredPoints - The number of points in the join 4180 - coveredPoints - The points in the join 4181 4182 Level: intermediate 4183 4184 Note: Currently, this is restricted to a single level join 4185 4186 Fortran Notes: 4187 Since it returns an array, this routine is only available in Fortran 90, and you must 4188 include petsc.h90 in your code. 4189 4190 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4191 4192 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4193 @*/ 4194 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4195 { 4196 DM_Plex *mesh = (DM_Plex*) dm->data; 4197 PetscInt *join[2]; 4198 PetscInt joinSize, i = 0; 4199 PetscInt dof, off, p, c, m; 4200 PetscInt maxSupportSize; 4201 4202 PetscFunctionBegin; 4203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4204 PetscValidIntPointer(points, 3); 4205 PetscValidIntPointer(numCoveredPoints, 4); 4206 PetscValidPointer(coveredPoints, 5); 4207 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4208 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4209 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4210 /* Copy in support of first point */ 4211 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4212 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4213 for (joinSize = 0; joinSize < dof; ++joinSize) { 4214 join[i][joinSize] = mesh->supports[off+joinSize]; 4215 } 4216 /* Check each successive support */ 4217 for (p = 1; p < numPoints; ++p) { 4218 PetscInt newJoinSize = 0; 4219 4220 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4221 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4222 for (c = 0; c < dof; ++c) { 4223 const PetscInt point = mesh->supports[off+c]; 4224 4225 for (m = 0; m < joinSize; ++m) { 4226 if (point == join[i][m]) { 4227 join[1-i][newJoinSize++] = point; 4228 break; 4229 } 4230 } 4231 } 4232 joinSize = newJoinSize; 4233 i = 1-i; 4234 } 4235 *numCoveredPoints = joinSize; 4236 *coveredPoints = join[i]; 4237 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4238 PetscFunctionReturn(0); 4239 } 4240 4241 /*@C 4242 DMPlexRestoreJoin - Restore an array for the join of the set of points 4243 4244 Not Collective 4245 4246 Input Parameters: 4247 + dm - The DMPlex object 4248 . numPoints - The number of input points for the join 4249 - points - The input points 4250 4251 Output Parameters: 4252 + numCoveredPoints - The number of points in the join 4253 - coveredPoints - The points in the join 4254 4255 Fortran Notes: 4256 Since it returns an array, this routine is only available in Fortran 90, and you must 4257 include petsc.h90 in your code. 4258 4259 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4260 4261 Level: intermediate 4262 4263 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4264 @*/ 4265 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4266 { 4267 PetscFunctionBegin; 4268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4269 if (points) PetscValidIntPointer(points,3); 4270 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4271 PetscValidPointer(coveredPoints, 5); 4272 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4273 if (numCoveredPoints) *numCoveredPoints = 0; 4274 PetscFunctionReturn(0); 4275 } 4276 4277 /*@C 4278 DMPlexGetFullJoin - Get an array for the join of the set of points 4279 4280 Not Collective 4281 4282 Input Parameters: 4283 + dm - The DMPlex object 4284 . numPoints - The number of input points for the join 4285 - points - The input points 4286 4287 Output Parameters: 4288 + numCoveredPoints - The number of points in the join 4289 - coveredPoints - The points in the join 4290 4291 Fortran Notes: 4292 Since it returns an array, this routine is only available in Fortran 90, and you must 4293 include petsc.h90 in your code. 4294 4295 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4296 4297 Level: intermediate 4298 4299 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4300 @*/ 4301 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4302 { 4303 PetscInt *offsets, **closures; 4304 PetscInt *join[2]; 4305 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4306 PetscInt p, d, c, m, ms; 4307 4308 PetscFunctionBegin; 4309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4310 PetscValidIntPointer(points, 3); 4311 PetscValidIntPointer(numCoveredPoints, 4); 4312 PetscValidPointer(coveredPoints, 5); 4313 4314 PetscCall(DMPlexGetDepth(dm, &depth)); 4315 PetscCall(PetscCalloc1(numPoints, &closures)); 4316 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4317 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4318 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4319 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4320 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4321 4322 for (p = 0; p < numPoints; ++p) { 4323 PetscInt closureSize; 4324 4325 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4326 4327 offsets[p*(depth+2)+0] = 0; 4328 for (d = 0; d < depth+1; ++d) { 4329 PetscInt pStart, pEnd, i; 4330 4331 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4332 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4333 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4334 offsets[p*(depth+2)+d+1] = i; 4335 break; 4336 } 4337 } 4338 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4339 } 4340 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); 4341 } 4342 for (d = 0; d < depth+1; ++d) { 4343 PetscInt dof; 4344 4345 /* Copy in support of first point */ 4346 dof = offsets[d+1] - offsets[d]; 4347 for (joinSize = 0; joinSize < dof; ++joinSize) { 4348 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4349 } 4350 /* Check each successive cone */ 4351 for (p = 1; p < numPoints && joinSize; ++p) { 4352 PetscInt newJoinSize = 0; 4353 4354 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4355 for (c = 0; c < dof; ++c) { 4356 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4357 4358 for (m = 0; m < joinSize; ++m) { 4359 if (point == join[i][m]) { 4360 join[1-i][newJoinSize++] = point; 4361 break; 4362 } 4363 } 4364 } 4365 joinSize = newJoinSize; 4366 i = 1-i; 4367 } 4368 if (joinSize) break; 4369 } 4370 *numCoveredPoints = joinSize; 4371 *coveredPoints = join[i]; 4372 for (p = 0; p < numPoints; ++p) { 4373 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4374 } 4375 PetscCall(PetscFree(closures)); 4376 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4377 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4378 PetscFunctionReturn(0); 4379 } 4380 4381 /*@C 4382 DMPlexGetMeet - Get an array for the meet of the set of points 4383 4384 Not Collective 4385 4386 Input Parameters: 4387 + dm - The DMPlex object 4388 . numPoints - The number of input points for the meet 4389 - points - The input points 4390 4391 Output Parameters: 4392 + numCoveredPoints - The number of points in the meet 4393 - coveredPoints - The points in the meet 4394 4395 Level: intermediate 4396 4397 Note: Currently, this is restricted to a single level meet 4398 4399 Fortran Notes: 4400 Since it returns an array, this routine is only available in Fortran 90, and you must 4401 include petsc.h90 in your code. 4402 4403 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4404 4405 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4406 @*/ 4407 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4408 { 4409 DM_Plex *mesh = (DM_Plex*) dm->data; 4410 PetscInt *meet[2]; 4411 PetscInt meetSize, i = 0; 4412 PetscInt dof, off, p, c, m; 4413 PetscInt maxConeSize; 4414 4415 PetscFunctionBegin; 4416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4417 PetscValidIntPointer(points, 3); 4418 PetscValidIntPointer(numCoveringPoints, 4); 4419 PetscValidPointer(coveringPoints, 5); 4420 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4421 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4422 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4423 /* Copy in cone of first point */ 4424 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4425 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4426 for (meetSize = 0; meetSize < dof; ++meetSize) { 4427 meet[i][meetSize] = mesh->cones[off+meetSize]; 4428 } 4429 /* Check each successive cone */ 4430 for (p = 1; p < numPoints; ++p) { 4431 PetscInt newMeetSize = 0; 4432 4433 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4434 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4435 for (c = 0; c < dof; ++c) { 4436 const PetscInt point = mesh->cones[off+c]; 4437 4438 for (m = 0; m < meetSize; ++m) { 4439 if (point == meet[i][m]) { 4440 meet[1-i][newMeetSize++] = point; 4441 break; 4442 } 4443 } 4444 } 4445 meetSize = newMeetSize; 4446 i = 1-i; 4447 } 4448 *numCoveringPoints = meetSize; 4449 *coveringPoints = meet[i]; 4450 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4451 PetscFunctionReturn(0); 4452 } 4453 4454 /*@C 4455 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4456 4457 Not Collective 4458 4459 Input Parameters: 4460 + dm - The DMPlex object 4461 . numPoints - The number of input points for the meet 4462 - points - The input points 4463 4464 Output Parameters: 4465 + numCoveredPoints - The number of points in the meet 4466 - coveredPoints - The points in the meet 4467 4468 Level: intermediate 4469 4470 Fortran Notes: 4471 Since it returns an array, this routine is only available in Fortran 90, and you must 4472 include petsc.h90 in your code. 4473 4474 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4475 4476 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4477 @*/ 4478 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4479 { 4480 PetscFunctionBegin; 4481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4482 if (points) PetscValidIntPointer(points,3); 4483 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4484 PetscValidPointer(coveredPoints,5); 4485 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4486 if (numCoveredPoints) *numCoveredPoints = 0; 4487 PetscFunctionReturn(0); 4488 } 4489 4490 /*@C 4491 DMPlexGetFullMeet - Get an array for the meet of the set of points 4492 4493 Not Collective 4494 4495 Input Parameters: 4496 + dm - The DMPlex object 4497 . numPoints - The number of input points for the meet 4498 - points - The input points 4499 4500 Output Parameters: 4501 + numCoveredPoints - The number of points in the meet 4502 - coveredPoints - The points in the meet 4503 4504 Level: intermediate 4505 4506 Fortran Notes: 4507 Since it returns an array, this routine is only available in Fortran 90, and you must 4508 include petsc.h90 in your code. 4509 4510 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4511 4512 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4513 @*/ 4514 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4515 { 4516 PetscInt *offsets, **closures; 4517 PetscInt *meet[2]; 4518 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4519 PetscInt p, h, c, m, mc; 4520 4521 PetscFunctionBegin; 4522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4523 PetscValidIntPointer(points, 3); 4524 PetscValidIntPointer(numCoveredPoints, 4); 4525 PetscValidPointer(coveredPoints, 5); 4526 4527 PetscCall(DMPlexGetDepth(dm, &height)); 4528 PetscCall(PetscMalloc1(numPoints, &closures)); 4529 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4530 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4531 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4532 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4533 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4534 4535 for (p = 0; p < numPoints; ++p) { 4536 PetscInt closureSize; 4537 4538 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4539 4540 offsets[p*(height+2)+0] = 0; 4541 for (h = 0; h < height+1; ++h) { 4542 PetscInt pStart, pEnd, i; 4543 4544 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4545 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4546 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4547 offsets[p*(height+2)+h+1] = i; 4548 break; 4549 } 4550 } 4551 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4552 } 4553 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); 4554 } 4555 for (h = 0; h < height+1; ++h) { 4556 PetscInt dof; 4557 4558 /* Copy in cone of first point */ 4559 dof = offsets[h+1] - offsets[h]; 4560 for (meetSize = 0; meetSize < dof; ++meetSize) { 4561 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4562 } 4563 /* Check each successive cone */ 4564 for (p = 1; p < numPoints && meetSize; ++p) { 4565 PetscInt newMeetSize = 0; 4566 4567 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4568 for (c = 0; c < dof; ++c) { 4569 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4570 4571 for (m = 0; m < meetSize; ++m) { 4572 if (point == meet[i][m]) { 4573 meet[1-i][newMeetSize++] = point; 4574 break; 4575 } 4576 } 4577 } 4578 meetSize = newMeetSize; 4579 i = 1-i; 4580 } 4581 if (meetSize) break; 4582 } 4583 *numCoveredPoints = meetSize; 4584 *coveredPoints = meet[i]; 4585 for (p = 0; p < numPoints; ++p) { 4586 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4587 } 4588 PetscCall(PetscFree(closures)); 4589 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4590 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4591 PetscFunctionReturn(0); 4592 } 4593 4594 /*@C 4595 DMPlexEqual - Determine if two DMs have the same topology 4596 4597 Not Collective 4598 4599 Input Parameters: 4600 + dmA - A DMPlex object 4601 - dmB - A DMPlex object 4602 4603 Output Parameters: 4604 . equal - PETSC_TRUE if the topologies are identical 4605 4606 Level: intermediate 4607 4608 Notes: 4609 We are not solving graph isomorphism, so we do not permutation. 4610 4611 .seealso: `DMPlexGetCone()` 4612 @*/ 4613 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4614 { 4615 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4616 4617 PetscFunctionBegin; 4618 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4619 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4620 PetscValidBoolPointer(equal, 3); 4621 4622 *equal = PETSC_FALSE; 4623 PetscCall(DMPlexGetDepth(dmA, &depth)); 4624 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4625 if (depth != depthB) PetscFunctionReturn(0); 4626 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4627 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4628 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4629 for (p = pStart; p < pEnd; ++p) { 4630 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4631 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4632 4633 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4634 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4635 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4636 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4637 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4638 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4639 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4640 for (c = 0; c < coneSize; ++c) { 4641 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4642 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4643 } 4644 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4645 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4646 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4647 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4648 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4649 for (s = 0; s < supportSize; ++s) { 4650 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4651 } 4652 } 4653 *equal = PETSC_TRUE; 4654 PetscFunctionReturn(0); 4655 } 4656 4657 /*@C 4658 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4659 4660 Not Collective 4661 4662 Input Parameters: 4663 + dm - The DMPlex 4664 . cellDim - The cell dimension 4665 - numCorners - The number of vertices on a cell 4666 4667 Output Parameters: 4668 . numFaceVertices - The number of vertices on a face 4669 4670 Level: developer 4671 4672 Notes: 4673 Of course this can only work for a restricted set of symmetric shapes 4674 4675 .seealso: `DMPlexGetCone()` 4676 @*/ 4677 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4678 { 4679 MPI_Comm comm; 4680 4681 PetscFunctionBegin; 4682 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4683 PetscValidIntPointer(numFaceVertices,4); 4684 switch (cellDim) { 4685 case 0: 4686 *numFaceVertices = 0; 4687 break; 4688 case 1: 4689 *numFaceVertices = 1; 4690 break; 4691 case 2: 4692 switch (numCorners) { 4693 case 3: /* triangle */ 4694 *numFaceVertices = 2; /* Edge has 2 vertices */ 4695 break; 4696 case 4: /* quadrilateral */ 4697 *numFaceVertices = 2; /* Edge has 2 vertices */ 4698 break; 4699 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4700 *numFaceVertices = 3; /* Edge has 3 vertices */ 4701 break; 4702 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4703 *numFaceVertices = 3; /* Edge has 3 vertices */ 4704 break; 4705 default: 4706 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4707 } 4708 break; 4709 case 3: 4710 switch (numCorners) { 4711 case 4: /* tetradehdron */ 4712 *numFaceVertices = 3; /* Face has 3 vertices */ 4713 break; 4714 case 6: /* tet cohesive cells */ 4715 *numFaceVertices = 4; /* Face has 4 vertices */ 4716 break; 4717 case 8: /* hexahedron */ 4718 *numFaceVertices = 4; /* Face has 4 vertices */ 4719 break; 4720 case 9: /* tet cohesive Lagrange cells */ 4721 *numFaceVertices = 6; /* Face has 6 vertices */ 4722 break; 4723 case 10: /* quadratic tetrahedron */ 4724 *numFaceVertices = 6; /* Face has 6 vertices */ 4725 break; 4726 case 12: /* hex cohesive Lagrange cells */ 4727 *numFaceVertices = 6; /* Face has 6 vertices */ 4728 break; 4729 case 18: /* quadratic tet cohesive Lagrange cells */ 4730 *numFaceVertices = 6; /* Face has 6 vertices */ 4731 break; 4732 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4733 *numFaceVertices = 9; /* Face has 9 vertices */ 4734 break; 4735 default: 4736 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4737 } 4738 break; 4739 default: 4740 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4741 } 4742 PetscFunctionReturn(0); 4743 } 4744 4745 /*@ 4746 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4747 4748 Not Collective 4749 4750 Input Parameter: 4751 . dm - The DMPlex object 4752 4753 Output Parameter: 4754 . depthLabel - The DMLabel recording point depth 4755 4756 Level: developer 4757 4758 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4759 @*/ 4760 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4761 { 4762 PetscFunctionBegin; 4763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4764 PetscValidPointer(depthLabel, 2); 4765 *depthLabel = dm->depthLabel; 4766 PetscFunctionReturn(0); 4767 } 4768 4769 /*@ 4770 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4771 4772 Not Collective 4773 4774 Input Parameter: 4775 . dm - The DMPlex object 4776 4777 Output Parameter: 4778 . depth - The number of strata (breadth first levels) in the DAG 4779 4780 Level: developer 4781 4782 Notes: 4783 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4784 The point depth is described more in detail in DMPlexGetDepthStratum(). 4785 An empty mesh gives -1. 4786 4787 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4788 @*/ 4789 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4790 { 4791 DMLabel label; 4792 PetscInt d = 0; 4793 4794 PetscFunctionBegin; 4795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4796 PetscValidIntPointer(depth, 2); 4797 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4798 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4799 *depth = d-1; 4800 PetscFunctionReturn(0); 4801 } 4802 4803 /*@ 4804 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4805 4806 Not Collective 4807 4808 Input Parameters: 4809 + dm - The DMPlex object 4810 - depth - The requested depth 4811 4812 Output Parameters: 4813 + start - The first point at this depth 4814 - end - One beyond the last point at this depth 4815 4816 Notes: 4817 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4818 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4819 higher dimension, e.g., "edges". 4820 4821 Level: developer 4822 4823 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4824 @*/ 4825 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4826 { 4827 DMLabel label; 4828 PetscInt pStart, pEnd; 4829 4830 PetscFunctionBegin; 4831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4832 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4833 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4834 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4835 if (pStart == pEnd) PetscFunctionReturn(0); 4836 if (depth < 0) { 4837 if (start) *start = pStart; 4838 if (end) *end = pEnd; 4839 PetscFunctionReturn(0); 4840 } 4841 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4842 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4843 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4844 PetscFunctionReturn(0); 4845 } 4846 4847 /*@ 4848 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4849 4850 Not Collective 4851 4852 Input Parameters: 4853 + dm - The DMPlex object 4854 - height - The requested height 4855 4856 Output Parameters: 4857 + start - The first point at this height 4858 - end - One beyond the last point at this height 4859 4860 Notes: 4861 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4862 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4863 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4864 4865 Level: developer 4866 4867 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4868 @*/ 4869 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4870 { 4871 DMLabel label; 4872 PetscInt depth, pStart, pEnd; 4873 4874 PetscFunctionBegin; 4875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4876 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4877 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4878 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4879 if (pStart == pEnd) PetscFunctionReturn(0); 4880 if (height < 0) { 4881 if (start) *start = pStart; 4882 if (end) *end = pEnd; 4883 PetscFunctionReturn(0); 4884 } 4885 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4886 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4887 PetscCall(DMLabelGetNumValues(label, &depth)); 4888 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4889 PetscFunctionReturn(0); 4890 } 4891 4892 /*@ 4893 DMPlexGetPointDepth - Get the depth of a given point 4894 4895 Not Collective 4896 4897 Input Parameters: 4898 + dm - The DMPlex object 4899 - point - The point 4900 4901 Output Parameter: 4902 . depth - The depth of the point 4903 4904 Level: intermediate 4905 4906 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4907 @*/ 4908 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4909 { 4910 PetscFunctionBegin; 4911 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4912 PetscValidIntPointer(depth, 3); 4913 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4914 PetscFunctionReturn(0); 4915 } 4916 4917 /*@ 4918 DMPlexGetPointHeight - Get the height of a given point 4919 4920 Not Collective 4921 4922 Input Parameters: 4923 + dm - The DMPlex object 4924 - point - The point 4925 4926 Output Parameter: 4927 . height - The height of the point 4928 4929 Level: intermediate 4930 4931 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4932 @*/ 4933 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4934 { 4935 PetscInt n, pDepth; 4936 4937 PetscFunctionBegin; 4938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4939 PetscValidIntPointer(height, 3); 4940 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4941 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4942 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4943 PetscFunctionReturn(0); 4944 } 4945 4946 /*@ 4947 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4948 4949 Not Collective 4950 4951 Input Parameter: 4952 . dm - The DMPlex object 4953 4954 Output Parameter: 4955 . celltypeLabel - The DMLabel recording cell polytope type 4956 4957 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4958 DMCreateLabel(dm, "celltype") beforehand. 4959 4960 Level: developer 4961 4962 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4963 @*/ 4964 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4965 { 4966 PetscFunctionBegin; 4967 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4968 PetscValidPointer(celltypeLabel, 2); 4969 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4970 *celltypeLabel = dm->celltypeLabel; 4971 PetscFunctionReturn(0); 4972 } 4973 4974 /*@ 4975 DMPlexGetCellType - Get the polytope type of a given cell 4976 4977 Not Collective 4978 4979 Input Parameters: 4980 + dm - The DMPlex object 4981 - cell - The cell 4982 4983 Output Parameter: 4984 . celltype - The polytope type of the cell 4985 4986 Level: intermediate 4987 4988 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4989 @*/ 4990 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4991 { 4992 DMLabel label; 4993 PetscInt ct; 4994 4995 PetscFunctionBegin; 4996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4997 PetscValidPointer(celltype, 3); 4998 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4999 PetscCall(DMLabelGetValue(label, cell, &ct)); 5000 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5001 *celltype = (DMPolytopeType) ct; 5002 PetscFunctionReturn(0); 5003 } 5004 5005 /*@ 5006 DMPlexSetCellType - Set the polytope type of a given cell 5007 5008 Not Collective 5009 5010 Input Parameters: 5011 + dm - The DMPlex object 5012 . cell - The cell 5013 - celltype - The polytope type of the cell 5014 5015 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5016 is executed. This function will override the computed type. However, if automatic classification will not succeed 5017 and a user wants to manually specify all types, the classification must be disabled by calling 5018 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5019 5020 Level: advanced 5021 5022 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5023 @*/ 5024 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5025 { 5026 DMLabel label; 5027 5028 PetscFunctionBegin; 5029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5030 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5031 PetscCall(DMLabelSetValue(label, cell, celltype)); 5032 PetscFunctionReturn(0); 5033 } 5034 5035 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5036 { 5037 PetscSection section, s; 5038 Mat m; 5039 PetscInt maxHeight; 5040 5041 PetscFunctionBegin; 5042 PetscCall(DMClone(dm, cdm)); 5043 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5044 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5045 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5046 PetscCall(DMSetLocalSection(*cdm, section)); 5047 PetscCall(PetscSectionDestroy(§ion)); 5048 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5049 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5050 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5051 PetscCall(PetscSectionDestroy(&s)); 5052 PetscCall(MatDestroy(&m)); 5053 5054 PetscCall(DMSetNumFields(*cdm, 1)); 5055 PetscCall(DMCreateDS(*cdm)); 5056 PetscFunctionReturn(0); 5057 } 5058 5059 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5060 { 5061 Vec coordsLocal, cellCoordsLocal; 5062 DM coordsDM, cellCoordsDM; 5063 5064 PetscFunctionBegin; 5065 *field = NULL; 5066 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5067 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5068 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5069 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5070 if (coordsLocal && coordsDM) { 5071 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5072 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5073 } 5074 PetscFunctionReturn(0); 5075 } 5076 5077 /*@C 5078 DMPlexGetConeSection - Return a section which describes the layout of cone data 5079 5080 Not Collective 5081 5082 Input Parameters: 5083 . dm - The DMPlex object 5084 5085 Output Parameter: 5086 . section - The PetscSection object 5087 5088 Level: developer 5089 5090 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5091 @*/ 5092 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5093 { 5094 DM_Plex *mesh = (DM_Plex*) dm->data; 5095 5096 PetscFunctionBegin; 5097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5098 if (section) *section = mesh->coneSection; 5099 PetscFunctionReturn(0); 5100 } 5101 5102 /*@C 5103 DMPlexGetSupportSection - Return a section which describes the layout of support data 5104 5105 Not Collective 5106 5107 Input Parameters: 5108 . dm - The DMPlex object 5109 5110 Output Parameter: 5111 . section - The PetscSection object 5112 5113 Level: developer 5114 5115 .seealso: `DMPlexGetConeSection()` 5116 @*/ 5117 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5118 { 5119 DM_Plex *mesh = (DM_Plex*) dm->data; 5120 5121 PetscFunctionBegin; 5122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5123 if (section) *section = mesh->supportSection; 5124 PetscFunctionReturn(0); 5125 } 5126 5127 /*@C 5128 DMPlexGetCones - Return cone data 5129 5130 Not Collective 5131 5132 Input Parameters: 5133 . dm - The DMPlex object 5134 5135 Output Parameter: 5136 . cones - The cone for each point 5137 5138 Level: developer 5139 5140 .seealso: `DMPlexGetConeSection()` 5141 @*/ 5142 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5143 { 5144 DM_Plex *mesh = (DM_Plex*) dm->data; 5145 5146 PetscFunctionBegin; 5147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5148 if (cones) *cones = mesh->cones; 5149 PetscFunctionReturn(0); 5150 } 5151 5152 /*@C 5153 DMPlexGetConeOrientations - Return cone orientation data 5154 5155 Not Collective 5156 5157 Input Parameters: 5158 . dm - The DMPlex object 5159 5160 Output Parameter: 5161 . coneOrientations - The array of cone orientations for all points 5162 5163 Level: developer 5164 5165 Notes: 5166 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5167 5168 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5169 5170 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5171 @*/ 5172 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5173 { 5174 DM_Plex *mesh = (DM_Plex*) dm->data; 5175 5176 PetscFunctionBegin; 5177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5178 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5179 PetscFunctionReturn(0); 5180 } 5181 5182 /******************************** FEM Support **********************************/ 5183 5184 /* 5185 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5186 representing a line in the section. 5187 */ 5188 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5189 { 5190 PetscFunctionBeginHot; 5191 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5192 if (line < 0) { 5193 *k = 0; 5194 *Nc = 0; 5195 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5196 *k = 1; 5197 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5198 /* An order k SEM disc has k-1 dofs on an edge */ 5199 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5200 *k = *k / *Nc + 1; 5201 } 5202 PetscFunctionReturn(0); 5203 } 5204 5205 /*@ 5206 5207 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5208 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5209 section provided (or the section of the DM). 5210 5211 Input Parameters: 5212 + dm - The DM 5213 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5214 - section - The PetscSection to reorder, or NULL for the default section 5215 5216 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5217 degree of the basis. 5218 5219 Example: 5220 A typical interpolated single-quad mesh might order points as 5221 .vb 5222 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5223 5224 v4 -- e6 -- v3 5225 | | 5226 e7 c0 e8 5227 | | 5228 v1 -- e5 -- v2 5229 .ve 5230 5231 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5232 dofs in the order of points, e.g., 5233 .vb 5234 c0 -> [0,1,2,3] 5235 v1 -> [4] 5236 ... 5237 e5 -> [8, 9] 5238 .ve 5239 5240 which corresponds to the dofs 5241 .vb 5242 6 10 11 7 5243 13 2 3 15 5244 12 0 1 14 5245 4 8 9 5 5246 .ve 5247 5248 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5249 .vb 5250 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5251 .ve 5252 5253 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5254 .vb 5255 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5256 .ve 5257 5258 Level: developer 5259 5260 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5261 @*/ 5262 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5263 { 5264 DMLabel label; 5265 PetscInt dim, depth = -1, eStart = -1, Nf; 5266 PetscBool vertexchart; 5267 5268 PetscFunctionBegin; 5269 PetscCall(DMGetDimension(dm, &dim)); 5270 if (dim < 1) PetscFunctionReturn(0); 5271 if (point < 0) { 5272 PetscInt sStart,sEnd; 5273 5274 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5275 point = sEnd-sStart ? sStart : point; 5276 } 5277 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5278 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5279 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5280 if (depth == 1) {eStart = point;} 5281 else if (depth == dim) { 5282 const PetscInt *cone; 5283 5284 PetscCall(DMPlexGetCone(dm, point, &cone)); 5285 if (dim == 2) eStart = cone[0]; 5286 else if (dim == 3) { 5287 const PetscInt *cone2; 5288 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5289 eStart = cone2[0]; 5290 } 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); 5291 } 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); 5292 { /* Determine whether the chart covers all points or just vertices. */ 5293 PetscInt pStart,pEnd,cStart,cEnd; 5294 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5295 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5296 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5297 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5298 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5299 } 5300 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5301 for (PetscInt d=1; d<=dim; d++) { 5302 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5303 PetscInt *perm; 5304 5305 for (f = 0; f < Nf; ++f) { 5306 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5307 size += PetscPowInt(k+1, d)*Nc; 5308 } 5309 PetscCall(PetscMalloc1(size, &perm)); 5310 for (f = 0; f < Nf; ++f) { 5311 switch (d) { 5312 case 1: 5313 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5314 /* 5315 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5316 We want [ vtx0; edge of length k-1; vtx1 ] 5317 */ 5318 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5319 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5320 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5321 foffset = offset; 5322 break; 5323 case 2: 5324 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5325 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5326 /* The SEM order is 5327 5328 v_lb, {e_b}, v_rb, 5329 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5330 v_lt, reverse {e_t}, v_rt 5331 */ 5332 { 5333 const PetscInt of = 0; 5334 const PetscInt oeb = of + PetscSqr(k-1); 5335 const PetscInt oer = oeb + (k-1); 5336 const PetscInt oet = oer + (k-1); 5337 const PetscInt oel = oet + (k-1); 5338 const PetscInt ovlb = oel + (k-1); 5339 const PetscInt ovrb = ovlb + 1; 5340 const PetscInt ovrt = ovrb + 1; 5341 const PetscInt ovlt = ovrt + 1; 5342 PetscInt o; 5343 5344 /* bottom */ 5345 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5346 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5348 /* middle */ 5349 for (i = 0; i < k-1; ++i) { 5350 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5351 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; 5352 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5353 } 5354 /* top */ 5355 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5356 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5357 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5358 foffset = offset; 5359 } 5360 break; 5361 case 3: 5362 /* The original hex closure is 5363 5364 {c, 5365 f_b, f_t, f_f, f_b, f_r, f_l, 5366 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5367 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5368 */ 5369 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5370 /* The SEM order is 5371 Bottom Slice 5372 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5373 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5374 v_blb, {e_bb}, v_brb, 5375 5376 Middle Slice (j) 5377 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5378 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5379 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5380 5381 Top Slice 5382 v_tlf, {e_tf}, v_trf, 5383 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5384 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5385 */ 5386 { 5387 const PetscInt oc = 0; 5388 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5389 const PetscInt oft = ofb + PetscSqr(k-1); 5390 const PetscInt off = oft + PetscSqr(k-1); 5391 const PetscInt ofk = off + PetscSqr(k-1); 5392 const PetscInt ofr = ofk + PetscSqr(k-1); 5393 const PetscInt ofl = ofr + PetscSqr(k-1); 5394 const PetscInt oebl = ofl + PetscSqr(k-1); 5395 const PetscInt oebb = oebl + (k-1); 5396 const PetscInt oebr = oebb + (k-1); 5397 const PetscInt oebf = oebr + (k-1); 5398 const PetscInt oetf = oebf + (k-1); 5399 const PetscInt oetr = oetf + (k-1); 5400 const PetscInt oetb = oetr + (k-1); 5401 const PetscInt oetl = oetb + (k-1); 5402 const PetscInt oerf = oetl + (k-1); 5403 const PetscInt oelf = oerf + (k-1); 5404 const PetscInt oelb = oelf + (k-1); 5405 const PetscInt oerb = oelb + (k-1); 5406 const PetscInt ovblf = oerb + (k-1); 5407 const PetscInt ovblb = ovblf + 1; 5408 const PetscInt ovbrb = ovblb + 1; 5409 const PetscInt ovbrf = ovbrb + 1; 5410 const PetscInt ovtlf = ovbrf + 1; 5411 const PetscInt ovtrf = ovtlf + 1; 5412 const PetscInt ovtrb = ovtrf + 1; 5413 const PetscInt ovtlb = ovtrb + 1; 5414 PetscInt o, n; 5415 5416 /* Bottom Slice */ 5417 /* bottom */ 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5419 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5421 /* middle */ 5422 for (i = 0; i < k-1; ++i) { 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5424 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;} 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5426 } 5427 /* top */ 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5429 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5431 5432 /* Middle Slice */ 5433 for (j = 0; j < k-1; ++j) { 5434 /* bottom */ 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5436 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; 5437 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5438 /* middle */ 5439 for (i = 0; i < k-1; ++i) { 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5441 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; 5442 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5443 } 5444 /* top */ 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5446 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; 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5448 } 5449 5450 /* Top Slice */ 5451 /* bottom */ 5452 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5453 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5454 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5455 /* middle */ 5456 for (i = 0; i < k-1; ++i) { 5457 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5458 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5459 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5460 } 5461 /* top */ 5462 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5463 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5464 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5465 5466 foffset = offset; 5467 } 5468 break; 5469 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5470 } 5471 } 5472 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5473 /* Check permutation */ 5474 { 5475 PetscInt *check; 5476 5477 PetscCall(PetscMalloc1(size, &check)); 5478 for (i = 0; i < size; ++i) { 5479 check[i] = -1; 5480 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5481 } 5482 for (i = 0; i < size; ++i) check[perm[i]] = i; 5483 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5484 PetscCall(PetscFree(check)); 5485 } 5486 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5487 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5488 PetscInt *loc_perm; 5489 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5490 for (PetscInt i=0; i<size; i++) { 5491 loc_perm[i] = perm[i]; 5492 loc_perm[size+i] = size + perm[i]; 5493 } 5494 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5495 } 5496 } 5497 PetscFunctionReturn(0); 5498 } 5499 5500 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5501 { 5502 PetscDS prob; 5503 PetscInt depth, Nf, h; 5504 DMLabel label; 5505 5506 PetscFunctionBeginHot; 5507 PetscCall(DMGetDS(dm, &prob)); 5508 Nf = prob->Nf; 5509 label = dm->depthLabel; 5510 *dspace = NULL; 5511 if (field < Nf) { 5512 PetscObject disc = prob->disc[field]; 5513 5514 if (disc->classid == PETSCFE_CLASSID) { 5515 PetscDualSpace dsp; 5516 5517 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5518 PetscCall(DMLabelGetNumValues(label,&depth)); 5519 PetscCall(DMLabelGetValue(label,point,&h)); 5520 h = depth - 1 - h; 5521 if (h) { 5522 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5523 } else { 5524 *dspace = dsp; 5525 } 5526 } 5527 } 5528 PetscFunctionReturn(0); 5529 } 5530 5531 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5532 { 5533 PetscScalar *array; 5534 const PetscScalar *vArray; 5535 const PetscInt *cone, *coneO; 5536 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5537 5538 PetscFunctionBeginHot; 5539 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5540 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5541 PetscCall(DMPlexGetCone(dm, point, &cone)); 5542 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5543 if (!values || !*values) { 5544 if ((point >= pStart) && (point < pEnd)) { 5545 PetscInt dof; 5546 5547 PetscCall(PetscSectionGetDof(section, point, &dof)); 5548 size += dof; 5549 } 5550 for (p = 0; p < numPoints; ++p) { 5551 const PetscInt cp = cone[p]; 5552 PetscInt dof; 5553 5554 if ((cp < pStart) || (cp >= pEnd)) continue; 5555 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5556 size += dof; 5557 } 5558 if (!values) { 5559 if (csize) *csize = size; 5560 PetscFunctionReturn(0); 5561 } 5562 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5563 } else { 5564 array = *values; 5565 } 5566 size = 0; 5567 PetscCall(VecGetArrayRead(v, &vArray)); 5568 if ((point >= pStart) && (point < pEnd)) { 5569 PetscInt dof, off, d; 5570 const PetscScalar *varr; 5571 5572 PetscCall(PetscSectionGetDof(section, point, &dof)); 5573 PetscCall(PetscSectionGetOffset(section, point, &off)); 5574 varr = &vArray[off]; 5575 for (d = 0; d < dof; ++d, ++offset) { 5576 array[offset] = varr[d]; 5577 } 5578 size += dof; 5579 } 5580 for (p = 0; p < numPoints; ++p) { 5581 const PetscInt cp = cone[p]; 5582 PetscInt o = coneO[p]; 5583 PetscInt dof, off, d; 5584 const PetscScalar *varr; 5585 5586 if ((cp < pStart) || (cp >= pEnd)) continue; 5587 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5588 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5589 varr = &vArray[off]; 5590 if (o >= 0) { 5591 for (d = 0; d < dof; ++d, ++offset) { 5592 array[offset] = varr[d]; 5593 } 5594 } else { 5595 for (d = dof-1; d >= 0; --d, ++offset) { 5596 array[offset] = varr[d]; 5597 } 5598 } 5599 size += dof; 5600 } 5601 PetscCall(VecRestoreArrayRead(v, &vArray)); 5602 if (!*values) { 5603 if (csize) *csize = size; 5604 *values = array; 5605 } else { 5606 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5607 *csize = size; 5608 } 5609 PetscFunctionReturn(0); 5610 } 5611 5612 /* Compress out points not in the section */ 5613 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5614 { 5615 const PetscInt np = *numPoints; 5616 PetscInt pStart, pEnd, p, q; 5617 5618 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5619 for (p = 0, q = 0; p < np; ++p) { 5620 const PetscInt r = points[p*2]; 5621 if ((r >= pStart) && (r < pEnd)) { 5622 points[q*2] = r; 5623 points[q*2+1] = points[p*2+1]; 5624 ++q; 5625 } 5626 } 5627 *numPoints = q; 5628 return 0; 5629 } 5630 5631 /* Compressed closure does not apply closure permutation */ 5632 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5633 { 5634 const PetscInt *cla = NULL; 5635 PetscInt np, *pts = NULL; 5636 5637 PetscFunctionBeginHot; 5638 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5639 if (*clPoints) { 5640 PetscInt dof, off; 5641 5642 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5643 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5644 PetscCall(ISGetIndices(*clPoints, &cla)); 5645 np = dof/2; 5646 pts = (PetscInt *) &cla[off]; 5647 } else { 5648 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5649 PetscCall(CompressPoints_Private(section, &np, pts)); 5650 } 5651 *numPoints = np; 5652 *points = pts; 5653 *clp = cla; 5654 PetscFunctionReturn(0); 5655 } 5656 5657 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5658 { 5659 PetscFunctionBeginHot; 5660 if (!*clPoints) { 5661 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5662 } else { 5663 PetscCall(ISRestoreIndices(*clPoints, clp)); 5664 } 5665 *numPoints = 0; 5666 *points = NULL; 5667 *clSec = NULL; 5668 *clPoints = NULL; 5669 *clp = NULL; 5670 PetscFunctionReturn(0); 5671 } 5672 5673 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5674 { 5675 PetscInt offset = 0, p; 5676 const PetscInt **perms = NULL; 5677 const PetscScalar **flips = NULL; 5678 5679 PetscFunctionBeginHot; 5680 *size = 0; 5681 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5682 for (p = 0; p < numPoints; p++) { 5683 const PetscInt point = points[2*p]; 5684 const PetscInt *perm = perms ? perms[p] : NULL; 5685 const PetscScalar *flip = flips ? flips[p] : NULL; 5686 PetscInt dof, off, d; 5687 const PetscScalar *varr; 5688 5689 PetscCall(PetscSectionGetDof(section, point, &dof)); 5690 PetscCall(PetscSectionGetOffset(section, point, &off)); 5691 varr = &vArray[off]; 5692 if (clperm) { 5693 if (perm) { 5694 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5695 } else { 5696 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5697 } 5698 if (flip) { 5699 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5700 } 5701 } else { 5702 if (perm) { 5703 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5704 } else { 5705 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5706 } 5707 if (flip) { 5708 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5709 } 5710 } 5711 offset += dof; 5712 } 5713 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5714 *size = offset; 5715 PetscFunctionReturn(0); 5716 } 5717 5718 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[]) 5719 { 5720 PetscInt offset = 0, f; 5721 5722 PetscFunctionBeginHot; 5723 *size = 0; 5724 for (f = 0; f < numFields; ++f) { 5725 PetscInt p; 5726 const PetscInt **perms = NULL; 5727 const PetscScalar **flips = NULL; 5728 5729 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5730 for (p = 0; p < numPoints; p++) { 5731 const PetscInt point = points[2*p]; 5732 PetscInt fdof, foff, b; 5733 const PetscScalar *varr; 5734 const PetscInt *perm = perms ? perms[p] : NULL; 5735 const PetscScalar *flip = flips ? flips[p] : NULL; 5736 5737 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5738 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5739 varr = &vArray[foff]; 5740 if (clperm) { 5741 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5742 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5743 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5744 } else { 5745 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5746 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5747 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5748 } 5749 offset += fdof; 5750 } 5751 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5752 } 5753 *size = offset; 5754 PetscFunctionReturn(0); 5755 } 5756 5757 /*@C 5758 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5759 5760 Not collective 5761 5762 Input Parameters: 5763 + dm - The DM 5764 . section - The section describing the layout in v, or NULL to use the default section 5765 . v - The local vector 5766 - point - The point in the DM 5767 5768 Input/Output Parameters: 5769 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5770 - values - An array to use for the values, or NULL to have it allocated automatically; 5771 if the user provided NULL, it is a borrowed array and should not be freed 5772 5773 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5774 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5775 $ assembly function, and a user may already have allocated storage for this operation. 5776 $ 5777 $ A typical use could be 5778 $ 5779 $ values = NULL; 5780 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5781 $ for (cl = 0; cl < clSize; ++cl) { 5782 $ <Compute on closure> 5783 $ } 5784 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5785 $ 5786 $ or 5787 $ 5788 $ PetscMalloc1(clMaxSize, &values); 5789 $ for (p = pStart; p < pEnd; ++p) { 5790 $ clSize = clMaxSize; 5791 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5792 $ for (cl = 0; cl < clSize; ++cl) { 5793 $ <Compute on closure> 5794 $ } 5795 $ } 5796 $ PetscFree(values); 5797 5798 Fortran Notes: 5799 Since it returns an array, this routine is only available in Fortran 90, and you must 5800 include petsc.h90 in your code. 5801 5802 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5803 5804 Level: intermediate 5805 5806 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5807 @*/ 5808 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5809 { 5810 PetscSection clSection; 5811 IS clPoints; 5812 PetscInt *points = NULL; 5813 const PetscInt *clp, *perm; 5814 PetscInt depth, numFields, numPoints, asize; 5815 5816 PetscFunctionBeginHot; 5817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5818 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5819 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5820 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5821 PetscCall(DMPlexGetDepth(dm, &depth)); 5822 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5823 if (depth == 1 && numFields < 2) { 5824 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5825 PetscFunctionReturn(0); 5826 } 5827 /* Get points */ 5828 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5829 /* Get sizes */ 5830 asize = 0; 5831 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5832 PetscInt dof; 5833 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5834 asize += dof; 5835 } 5836 if (values) { 5837 const PetscScalar *vArray; 5838 PetscInt size; 5839 5840 if (*values) { 5841 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); 5842 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5843 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5844 PetscCall(VecGetArrayRead(v, &vArray)); 5845 /* Get values */ 5846 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5847 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5848 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5849 /* Cleanup array */ 5850 PetscCall(VecRestoreArrayRead(v, &vArray)); 5851 } 5852 if (csize) *csize = asize; 5853 /* Cleanup points */ 5854 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5855 PetscFunctionReturn(0); 5856 } 5857 5858 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5859 { 5860 DMLabel depthLabel; 5861 PetscSection clSection; 5862 IS clPoints; 5863 PetscScalar *array; 5864 const PetscScalar *vArray; 5865 PetscInt *points = NULL; 5866 const PetscInt *clp, *perm = NULL; 5867 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5868 5869 PetscFunctionBeginHot; 5870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5871 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5872 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5873 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5874 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5875 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5876 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5877 if (mdepth == 1 && numFields < 2) { 5878 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5879 PetscFunctionReturn(0); 5880 } 5881 /* Get points */ 5882 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5883 for (clsize=0,p=0; p<Np; p++) { 5884 PetscInt dof; 5885 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5886 clsize += dof; 5887 } 5888 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5889 /* Filter points */ 5890 for (p = 0; p < numPoints*2; p += 2) { 5891 PetscInt dep; 5892 5893 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5894 if (dep != depth) continue; 5895 points[Np*2+0] = points[p]; 5896 points[Np*2+1] = points[p+1]; 5897 ++Np; 5898 } 5899 /* Get array */ 5900 if (!values || !*values) { 5901 PetscInt asize = 0, dof; 5902 5903 for (p = 0; p < Np*2; p += 2) { 5904 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5905 asize += dof; 5906 } 5907 if (!values) { 5908 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5909 if (csize) *csize = asize; 5910 PetscFunctionReturn(0); 5911 } 5912 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5913 } else { 5914 array = *values; 5915 } 5916 PetscCall(VecGetArrayRead(v, &vArray)); 5917 /* Get values */ 5918 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5919 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5920 /* Cleanup points */ 5921 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5922 /* Cleanup array */ 5923 PetscCall(VecRestoreArrayRead(v, &vArray)); 5924 if (!*values) { 5925 if (csize) *csize = size; 5926 *values = array; 5927 } else { 5928 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5929 *csize = size; 5930 } 5931 PetscFunctionReturn(0); 5932 } 5933 5934 /*@C 5935 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5936 5937 Not collective 5938 5939 Input Parameters: 5940 + dm - The DM 5941 . section - The section describing the layout in v, or NULL to use the default section 5942 . v - The local vector 5943 . point - The point in the DM 5944 . csize - The number of values in the closure, or NULL 5945 - values - The array of values, which is a borrowed array and should not be freed 5946 5947 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5948 5949 Fortran Notes: 5950 Since it returns an array, this routine is only available in Fortran 90, and you must 5951 include petsc.h90 in your code. 5952 5953 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5954 5955 Level: intermediate 5956 5957 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5958 @*/ 5959 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5960 { 5961 PetscInt size = 0; 5962 5963 PetscFunctionBegin; 5964 /* Should work without recalculating size */ 5965 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5966 *values = NULL; 5967 PetscFunctionReturn(0); 5968 } 5969 5970 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5971 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5972 5973 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[]) 5974 { 5975 PetscInt cdof; /* The number of constraints on this point */ 5976 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5977 PetscScalar *a; 5978 PetscInt off, cind = 0, k; 5979 5980 PetscFunctionBegin; 5981 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5982 PetscCall(PetscSectionGetOffset(section, point, &off)); 5983 a = &array[off]; 5984 if (!cdof || setBC) { 5985 if (clperm) { 5986 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5987 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5988 } else { 5989 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5990 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5991 } 5992 } else { 5993 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5994 if (clperm) { 5995 if (perm) {for (k = 0; k < dof; ++k) { 5996 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5997 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5998 } 5999 } else { 6000 for (k = 0; k < dof; ++k) { 6001 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6002 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6003 } 6004 } 6005 } else { 6006 if (perm) { 6007 for (k = 0; k < dof; ++k) { 6008 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6009 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6010 } 6011 } else { 6012 for (k = 0; k < dof; ++k) { 6013 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6014 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6015 } 6016 } 6017 } 6018 } 6019 PetscFunctionReturn(0); 6020 } 6021 6022 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[]) 6023 { 6024 PetscInt cdof; /* The number of constraints on this point */ 6025 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6026 PetscScalar *a; 6027 PetscInt off, cind = 0, k; 6028 6029 PetscFunctionBegin; 6030 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6031 PetscCall(PetscSectionGetOffset(section, point, &off)); 6032 a = &array[off]; 6033 if (cdof) { 6034 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6035 if (clperm) { 6036 if (perm) { 6037 for (k = 0; k < dof; ++k) { 6038 if ((cind < cdof) && (k == cdofs[cind])) { 6039 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6040 cind++; 6041 } 6042 } 6043 } else { 6044 for (k = 0; k < dof; ++k) { 6045 if ((cind < cdof) && (k == cdofs[cind])) { 6046 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6047 cind++; 6048 } 6049 } 6050 } 6051 } else { 6052 if (perm) { 6053 for (k = 0; k < dof; ++k) { 6054 if ((cind < cdof) && (k == cdofs[cind])) { 6055 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6056 cind++; 6057 } 6058 } 6059 } else { 6060 for (k = 0; k < dof; ++k) { 6061 if ((cind < cdof) && (k == cdofs[cind])) { 6062 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6063 cind++; 6064 } 6065 } 6066 } 6067 } 6068 } 6069 PetscFunctionReturn(0); 6070 } 6071 6072 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[]) 6073 { 6074 PetscScalar *a; 6075 PetscInt fdof, foff, fcdof, foffset = *offset; 6076 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6077 PetscInt cind = 0, b; 6078 6079 PetscFunctionBegin; 6080 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6081 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6082 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6083 a = &array[foff]; 6084 if (!fcdof || setBC) { 6085 if (clperm) { 6086 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6087 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6088 } else { 6089 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6090 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6091 } 6092 } else { 6093 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6094 if (clperm) { 6095 if (perm) { 6096 for (b = 0; b < fdof; b++) { 6097 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6098 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6099 } 6100 } else { 6101 for (b = 0; b < fdof; b++) { 6102 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6103 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6104 } 6105 } 6106 } else { 6107 if (perm) { 6108 for (b = 0; b < fdof; b++) { 6109 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6110 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6111 } 6112 } else { 6113 for (b = 0; b < fdof; b++) { 6114 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6115 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6116 } 6117 } 6118 } 6119 } 6120 *offset += fdof; 6121 PetscFunctionReturn(0); 6122 } 6123 6124 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[]) 6125 { 6126 PetscScalar *a; 6127 PetscInt fdof, foff, fcdof, foffset = *offset; 6128 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6129 PetscInt Nc, cind = 0, ncind = 0, b; 6130 PetscBool ncSet, fcSet; 6131 6132 PetscFunctionBegin; 6133 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6134 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6135 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6136 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6137 a = &array[foff]; 6138 if (fcdof) { 6139 /* We just override fcdof and fcdofs with Ncc and comps */ 6140 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6141 if (clperm) { 6142 if (perm) { 6143 if (comps) { 6144 for (b = 0; b < fdof; b++) { 6145 ncSet = fcSet = PETSC_FALSE; 6146 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6147 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6148 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6149 } 6150 } else { 6151 for (b = 0; b < fdof; b++) { 6152 if ((cind < fcdof) && (b == fcdofs[cind])) { 6153 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6154 ++cind; 6155 } 6156 } 6157 } 6158 } else { 6159 if (comps) { 6160 for (b = 0; b < fdof; b++) { 6161 ncSet = fcSet = PETSC_FALSE; 6162 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6163 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6164 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6165 } 6166 } else { 6167 for (b = 0; b < fdof; b++) { 6168 if ((cind < fcdof) && (b == fcdofs[cind])) { 6169 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6170 ++cind; 6171 } 6172 } 6173 } 6174 } 6175 } else { 6176 if (perm) { 6177 if (comps) { 6178 for (b = 0; b < fdof; b++) { 6179 ncSet = fcSet = PETSC_FALSE; 6180 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6181 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6182 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6183 } 6184 } else { 6185 for (b = 0; b < fdof; b++) { 6186 if ((cind < fcdof) && (b == fcdofs[cind])) { 6187 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6188 ++cind; 6189 } 6190 } 6191 } 6192 } else { 6193 if (comps) { 6194 for (b = 0; b < fdof; b++) { 6195 ncSet = fcSet = PETSC_FALSE; 6196 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6197 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6198 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6199 } 6200 } else { 6201 for (b = 0; b < fdof; b++) { 6202 if ((cind < fcdof) && (b == fcdofs[cind])) { 6203 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6204 ++cind; 6205 } 6206 } 6207 } 6208 } 6209 } 6210 } 6211 *offset += fdof; 6212 PetscFunctionReturn(0); 6213 } 6214 6215 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6216 { 6217 PetscScalar *array; 6218 const PetscInt *cone, *coneO; 6219 PetscInt pStart, pEnd, p, numPoints, off, dof; 6220 6221 PetscFunctionBeginHot; 6222 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6223 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6224 PetscCall(DMPlexGetCone(dm, point, &cone)); 6225 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6226 PetscCall(VecGetArray(v, &array)); 6227 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6228 const PetscInt cp = !p ? point : cone[p-1]; 6229 const PetscInt o = !p ? 0 : coneO[p-1]; 6230 6231 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6232 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6233 /* ADD_VALUES */ 6234 { 6235 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6236 PetscScalar *a; 6237 PetscInt cdof, coff, cind = 0, k; 6238 6239 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6240 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6241 a = &array[coff]; 6242 if (!cdof) { 6243 if (o >= 0) { 6244 for (k = 0; k < dof; ++k) { 6245 a[k] += values[off+k]; 6246 } 6247 } else { 6248 for (k = 0; k < dof; ++k) { 6249 a[k] += values[off+dof-k-1]; 6250 } 6251 } 6252 } else { 6253 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6254 if (o >= 0) { 6255 for (k = 0; k < dof; ++k) { 6256 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6257 a[k] += values[off+k]; 6258 } 6259 } else { 6260 for (k = 0; k < dof; ++k) { 6261 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6262 a[k] += values[off+dof-k-1]; 6263 } 6264 } 6265 } 6266 } 6267 } 6268 PetscCall(VecRestoreArray(v, &array)); 6269 PetscFunctionReturn(0); 6270 } 6271 6272 /*@C 6273 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6274 6275 Not collective 6276 6277 Input Parameters: 6278 + dm - The DM 6279 . section - The section describing the layout in v, or NULL to use the default section 6280 . v - The local vector 6281 . point - The point in the DM 6282 . values - The array of values 6283 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6284 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6285 6286 Fortran Notes: 6287 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6288 6289 Level: intermediate 6290 6291 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6292 @*/ 6293 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6294 { 6295 PetscSection clSection; 6296 IS clPoints; 6297 PetscScalar *array; 6298 PetscInt *points = NULL; 6299 const PetscInt *clp, *clperm = NULL; 6300 PetscInt depth, numFields, numPoints, p, clsize; 6301 6302 PetscFunctionBeginHot; 6303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6304 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6305 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6306 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6307 PetscCall(DMPlexGetDepth(dm, &depth)); 6308 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6309 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6310 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6311 PetscFunctionReturn(0); 6312 } 6313 /* Get points */ 6314 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6315 for (clsize=0,p=0; p<numPoints; p++) { 6316 PetscInt dof; 6317 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6318 clsize += dof; 6319 } 6320 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6321 /* Get array */ 6322 PetscCall(VecGetArray(v, &array)); 6323 /* Get values */ 6324 if (numFields > 0) { 6325 PetscInt offset = 0, f; 6326 for (f = 0; f < numFields; ++f) { 6327 const PetscInt **perms = NULL; 6328 const PetscScalar **flips = NULL; 6329 6330 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6331 switch (mode) { 6332 case INSERT_VALUES: 6333 for (p = 0; p < numPoints; p++) { 6334 const PetscInt point = points[2*p]; 6335 const PetscInt *perm = perms ? perms[p] : NULL; 6336 const PetscScalar *flip = flips ? flips[p] : NULL; 6337 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6338 } break; 6339 case INSERT_ALL_VALUES: 6340 for (p = 0; p < numPoints; p++) { 6341 const PetscInt point = points[2*p]; 6342 const PetscInt *perm = perms ? perms[p] : NULL; 6343 const PetscScalar *flip = flips ? flips[p] : NULL; 6344 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6345 } break; 6346 case INSERT_BC_VALUES: 6347 for (p = 0; p < numPoints; p++) { 6348 const PetscInt point = points[2*p]; 6349 const PetscInt *perm = perms ? perms[p] : NULL; 6350 const PetscScalar *flip = flips ? flips[p] : NULL; 6351 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6352 } break; 6353 case ADD_VALUES: 6354 for (p = 0; p < numPoints; p++) { 6355 const PetscInt point = points[2*p]; 6356 const PetscInt *perm = perms ? perms[p] : NULL; 6357 const PetscScalar *flip = flips ? flips[p] : NULL; 6358 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6359 } break; 6360 case ADD_ALL_VALUES: 6361 for (p = 0; p < numPoints; p++) { 6362 const PetscInt point = points[2*p]; 6363 const PetscInt *perm = perms ? perms[p] : NULL; 6364 const PetscScalar *flip = flips ? flips[p] : NULL; 6365 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6366 } break; 6367 case ADD_BC_VALUES: 6368 for (p = 0; p < numPoints; p++) { 6369 const PetscInt point = points[2*p]; 6370 const PetscInt *perm = perms ? perms[p] : NULL; 6371 const PetscScalar *flip = flips ? flips[p] : NULL; 6372 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6373 } break; 6374 default: 6375 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6376 } 6377 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6378 } 6379 } else { 6380 PetscInt dof, off; 6381 const PetscInt **perms = NULL; 6382 const PetscScalar **flips = NULL; 6383 6384 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6385 switch (mode) { 6386 case INSERT_VALUES: 6387 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6388 const PetscInt point = points[2*p]; 6389 const PetscInt *perm = perms ? perms[p] : NULL; 6390 const PetscScalar *flip = flips ? flips[p] : NULL; 6391 PetscCall(PetscSectionGetDof(section, point, &dof)); 6392 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6393 } break; 6394 case INSERT_ALL_VALUES: 6395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6396 const PetscInt point = points[2*p]; 6397 const PetscInt *perm = perms ? perms[p] : NULL; 6398 const PetscScalar *flip = flips ? flips[p] : NULL; 6399 PetscCall(PetscSectionGetDof(section, point, &dof)); 6400 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6401 } break; 6402 case INSERT_BC_VALUES: 6403 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6404 const PetscInt point = points[2*p]; 6405 const PetscInt *perm = perms ? perms[p] : NULL; 6406 const PetscScalar *flip = flips ? flips[p] : NULL; 6407 PetscCall(PetscSectionGetDof(section, point, &dof)); 6408 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6409 } break; 6410 case ADD_VALUES: 6411 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6412 const PetscInt point = points[2*p]; 6413 const PetscInt *perm = perms ? perms[p] : NULL; 6414 const PetscScalar *flip = flips ? flips[p] : NULL; 6415 PetscCall(PetscSectionGetDof(section, point, &dof)); 6416 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6417 } break; 6418 case ADD_ALL_VALUES: 6419 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6420 const PetscInt point = points[2*p]; 6421 const PetscInt *perm = perms ? perms[p] : NULL; 6422 const PetscScalar *flip = flips ? flips[p] : NULL; 6423 PetscCall(PetscSectionGetDof(section, point, &dof)); 6424 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6425 } break; 6426 case ADD_BC_VALUES: 6427 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6428 const PetscInt point = points[2*p]; 6429 const PetscInt *perm = perms ? perms[p] : NULL; 6430 const PetscScalar *flip = flips ? flips[p] : NULL; 6431 PetscCall(PetscSectionGetDof(section, point, &dof)); 6432 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6433 } break; 6434 default: 6435 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6436 } 6437 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6438 } 6439 /* Cleanup points */ 6440 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6441 /* Cleanup array */ 6442 PetscCall(VecRestoreArray(v, &array)); 6443 PetscFunctionReturn(0); 6444 } 6445 6446 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6447 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6448 { 6449 PetscFunctionBegin; 6450 if (label) { 6451 PetscBool contains; 6452 PetscInt fdof; 6453 6454 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6455 if (!contains) { 6456 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6457 *offset += fdof; 6458 PetscFunctionReturn(1); 6459 } 6460 } 6461 PetscFunctionReturn(0); 6462 } 6463 6464 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6465 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) 6466 { 6467 PetscSection clSection; 6468 IS clPoints; 6469 PetscScalar *array; 6470 PetscInt *points = NULL; 6471 const PetscInt *clp; 6472 PetscInt numFields, numPoints, p; 6473 PetscInt offset = 0, f; 6474 6475 PetscFunctionBeginHot; 6476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6477 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6478 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6479 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6480 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6481 /* Get points */ 6482 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6483 /* Get array */ 6484 PetscCall(VecGetArray(v, &array)); 6485 /* Get values */ 6486 for (f = 0; f < numFields; ++f) { 6487 const PetscInt **perms = NULL; 6488 const PetscScalar **flips = NULL; 6489 6490 if (!fieldActive[f]) { 6491 for (p = 0; p < numPoints*2; p += 2) { 6492 PetscInt fdof; 6493 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6494 offset += fdof; 6495 } 6496 continue; 6497 } 6498 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6499 switch (mode) { 6500 case INSERT_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2*p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6506 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6507 } break; 6508 case INSERT_ALL_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2*p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6514 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6515 } break; 6516 case INSERT_BC_VALUES: 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2*p]; 6519 const PetscInt *perm = perms ? perms[p] : NULL; 6520 const PetscScalar *flip = flips ? flips[p] : NULL; 6521 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6522 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6523 } break; 6524 case ADD_VALUES: 6525 for (p = 0; p < numPoints; p++) { 6526 const PetscInt point = points[2*p]; 6527 const PetscInt *perm = perms ? perms[p] : NULL; 6528 const PetscScalar *flip = flips ? flips[p] : NULL; 6529 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6530 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6531 } break; 6532 case ADD_ALL_VALUES: 6533 for (p = 0; p < numPoints; p++) { 6534 const PetscInt point = points[2*p]; 6535 const PetscInt *perm = perms ? perms[p] : NULL; 6536 const PetscScalar *flip = flips ? flips[p] : NULL; 6537 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6538 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6539 } break; 6540 default: 6541 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6542 } 6543 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6544 } 6545 /* Cleanup points */ 6546 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6547 /* Cleanup array */ 6548 PetscCall(VecRestoreArray(v, &array)); 6549 PetscFunctionReturn(0); 6550 } 6551 6552 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6553 { 6554 PetscMPIInt rank; 6555 PetscInt i, j; 6556 6557 PetscFunctionBegin; 6558 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6559 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6560 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6561 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6562 numCIndices = numCIndices ? numCIndices : numRIndices; 6563 if (!values) PetscFunctionReturn(0); 6564 for (i = 0; i < numRIndices; i++) { 6565 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6566 for (j = 0; j < numCIndices; j++) { 6567 #if defined(PETSC_USE_COMPLEX) 6568 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6569 #else 6570 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6571 #endif 6572 } 6573 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6574 } 6575 PetscFunctionReturn(0); 6576 } 6577 6578 /* 6579 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6580 6581 Input Parameters: 6582 + section - The section for this data layout 6583 . islocal - Is the section (and thus indices being requested) local or global? 6584 . point - The point contributing dofs with these indices 6585 . off - The global offset of this point 6586 . loff - The local offset of each field 6587 . setBC - The flag determining whether to include indices of boundary values 6588 . perm - A permutation of the dofs on this point, or NULL 6589 - indperm - A permutation of the entire indices array, or NULL 6590 6591 Output Parameter: 6592 . indices - Indices for dofs on this point 6593 6594 Level: developer 6595 6596 Note: The indices could be local or global, depending on the value of 'off'. 6597 */ 6598 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6599 { 6600 PetscInt dof; /* The number of unknowns on this point */ 6601 PetscInt cdof; /* The number of constraints on this point */ 6602 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6603 PetscInt cind = 0, k; 6604 6605 PetscFunctionBegin; 6606 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6607 PetscCall(PetscSectionGetDof(section, point, &dof)); 6608 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6609 if (!cdof || setBC) { 6610 for (k = 0; k < dof; ++k) { 6611 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6612 const PetscInt ind = indperm ? indperm[preind] : preind; 6613 6614 indices[ind] = off + k; 6615 } 6616 } else { 6617 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6618 for (k = 0; k < dof; ++k) { 6619 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6620 const PetscInt ind = indperm ? indperm[preind] : preind; 6621 6622 if ((cind < cdof) && (k == cdofs[cind])) { 6623 /* Insert check for returning constrained indices */ 6624 indices[ind] = -(off+k+1); 6625 ++cind; 6626 } else { 6627 indices[ind] = off + k - (islocal ? 0 : cind); 6628 } 6629 } 6630 } 6631 *loff += dof; 6632 PetscFunctionReturn(0); 6633 } 6634 6635 /* 6636 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6637 6638 Input Parameters: 6639 + section - a section (global or local) 6640 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6641 . point - point within section 6642 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6643 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6644 . setBC - identify constrained (boundary condition) points via involution. 6645 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6646 . permsoff - offset 6647 - indperm - index permutation 6648 6649 Output Parameter: 6650 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6651 . indices - array to hold indices (as defined by section) of each dof associated with point 6652 6653 Notes: 6654 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6655 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6656 in the local vector. 6657 6658 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6659 significant). It is invalid to call with a global section and setBC=true. 6660 6661 Developer Note: 6662 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6663 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6664 offset could be obtained from the section instead of passing it explicitly as we do now. 6665 6666 Example: 6667 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6668 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6669 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6670 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. 6671 6672 Level: developer 6673 */ 6674 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[]) 6675 { 6676 PetscInt numFields, foff, f; 6677 6678 PetscFunctionBegin; 6679 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6680 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6681 for (f = 0, foff = 0; f < numFields; ++f) { 6682 PetscInt fdof, cfdof; 6683 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6684 PetscInt cind = 0, b; 6685 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6686 6687 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6688 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6689 if (!cfdof || setBC) { 6690 for (b = 0; b < fdof; ++b) { 6691 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6692 const PetscInt ind = indperm ? indperm[preind] : preind; 6693 6694 indices[ind] = off+foff+b; 6695 } 6696 } else { 6697 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6698 for (b = 0; b < fdof; ++b) { 6699 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6700 const PetscInt ind = indperm ? indperm[preind] : preind; 6701 6702 if ((cind < cfdof) && (b == fcdofs[cind])) { 6703 indices[ind] = -(off+foff+b+1); 6704 ++cind; 6705 } else { 6706 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6707 } 6708 } 6709 } 6710 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6711 foffs[f] += fdof; 6712 } 6713 PetscFunctionReturn(0); 6714 } 6715 6716 /* 6717 This version believes the globalSection offsets for each field, rather than just the point offset 6718 6719 . foffs - The offset into 'indices' for each field, since it is segregated by field 6720 6721 Notes: 6722 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6723 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6724 */ 6725 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6726 { 6727 PetscInt numFields, foff, f; 6728 6729 PetscFunctionBegin; 6730 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6731 for (f = 0; f < numFields; ++f) { 6732 PetscInt fdof, cfdof; 6733 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6734 PetscInt cind = 0, b; 6735 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6736 6737 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6738 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6739 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6740 if (!cfdof) { 6741 for (b = 0; b < fdof; ++b) { 6742 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6743 const PetscInt ind = indperm ? indperm[preind] : preind; 6744 6745 indices[ind] = foff+b; 6746 } 6747 } else { 6748 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6749 for (b = 0; b < fdof; ++b) { 6750 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6751 const PetscInt ind = indperm ? indperm[preind] : preind; 6752 6753 if ((cind < cfdof) && (b == fcdofs[cind])) { 6754 indices[ind] = -(foff+b+1); 6755 ++cind; 6756 } else { 6757 indices[ind] = foff+b-cind; 6758 } 6759 } 6760 } 6761 foffs[f] += fdof; 6762 } 6763 PetscFunctionReturn(0); 6764 } 6765 6766 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) 6767 { 6768 Mat cMat; 6769 PetscSection aSec, cSec; 6770 IS aIS; 6771 PetscInt aStart = -1, aEnd = -1; 6772 const PetscInt *anchors; 6773 PetscInt numFields, f, p, q, newP = 0; 6774 PetscInt newNumPoints = 0, newNumIndices = 0; 6775 PetscInt *newPoints, *indices, *newIndices; 6776 PetscInt maxAnchor, maxDof; 6777 PetscInt newOffsets[32]; 6778 PetscInt *pointMatOffsets[32]; 6779 PetscInt *newPointOffsets[32]; 6780 PetscScalar *pointMat[32]; 6781 PetscScalar *newValues=NULL,*tmpValues; 6782 PetscBool anyConstrained = PETSC_FALSE; 6783 6784 PetscFunctionBegin; 6785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6786 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6787 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6788 6789 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6790 /* if there are point-to-point constraints */ 6791 if (aSec) { 6792 PetscCall(PetscArrayzero(newOffsets, 32)); 6793 PetscCall(ISGetIndices(aIS,&anchors)); 6794 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6795 /* figure out how many points are going to be in the new element matrix 6796 * (we allow double counting, because it's all just going to be summed 6797 * into the global matrix anyway) */ 6798 for (p = 0; p < 2*numPoints; p+=2) { 6799 PetscInt b = points[p]; 6800 PetscInt bDof = 0, bSecDof; 6801 6802 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6803 if (!bSecDof) { 6804 continue; 6805 } 6806 if (b >= aStart && b < aEnd) { 6807 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6808 } 6809 if (bDof) { 6810 /* this point is constrained */ 6811 /* it is going to be replaced by its anchors */ 6812 PetscInt bOff, q; 6813 6814 anyConstrained = PETSC_TRUE; 6815 newNumPoints += bDof; 6816 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6817 for (q = 0; q < bDof; q++) { 6818 PetscInt a = anchors[bOff + q]; 6819 PetscInt aDof; 6820 6821 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6822 newNumIndices += aDof; 6823 for (f = 0; f < numFields; ++f) { 6824 PetscInt fDof; 6825 6826 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6827 newOffsets[f+1] += fDof; 6828 } 6829 } 6830 } 6831 else { 6832 /* this point is not constrained */ 6833 newNumPoints++; 6834 newNumIndices += bSecDof; 6835 for (f = 0; f < numFields; ++f) { 6836 PetscInt fDof; 6837 6838 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6839 newOffsets[f+1] += fDof; 6840 } 6841 } 6842 } 6843 } 6844 if (!anyConstrained) { 6845 if (outNumPoints) *outNumPoints = 0; 6846 if (outNumIndices) *outNumIndices = 0; 6847 if (outPoints) *outPoints = NULL; 6848 if (outValues) *outValues = NULL; 6849 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6850 PetscFunctionReturn(0); 6851 } 6852 6853 if (outNumPoints) *outNumPoints = newNumPoints; 6854 if (outNumIndices) *outNumIndices = newNumIndices; 6855 6856 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6857 6858 if (!outPoints && !outValues) { 6859 if (offsets) { 6860 for (f = 0; f <= numFields; f++) { 6861 offsets[f] = newOffsets[f]; 6862 } 6863 } 6864 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6865 PetscFunctionReturn(0); 6866 } 6867 6868 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6869 6870 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6871 6872 /* workspaces */ 6873 if (numFields) { 6874 for (f = 0; f < numFields; f++) { 6875 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6876 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6877 } 6878 } 6879 else { 6880 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6881 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6882 } 6883 6884 /* get workspaces for the point-to-point matrices */ 6885 if (numFields) { 6886 PetscInt totalOffset, totalMatOffset; 6887 6888 for (p = 0; p < numPoints; p++) { 6889 PetscInt b = points[2*p]; 6890 PetscInt bDof = 0, bSecDof; 6891 6892 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6893 if (!bSecDof) { 6894 for (f = 0; f < numFields; f++) { 6895 newPointOffsets[f][p + 1] = 0; 6896 pointMatOffsets[f][p + 1] = 0; 6897 } 6898 continue; 6899 } 6900 if (b >= aStart && b < aEnd) { 6901 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6902 } 6903 if (bDof) { 6904 for (f = 0; f < numFields; f++) { 6905 PetscInt fDof, q, bOff, allFDof = 0; 6906 6907 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6908 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6909 for (q = 0; q < bDof; q++) { 6910 PetscInt a = anchors[bOff + q]; 6911 PetscInt aFDof; 6912 6913 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6914 allFDof += aFDof; 6915 } 6916 newPointOffsets[f][p+1] = allFDof; 6917 pointMatOffsets[f][p+1] = fDof * allFDof; 6918 } 6919 } 6920 else { 6921 for (f = 0; f < numFields; f++) { 6922 PetscInt fDof; 6923 6924 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6925 newPointOffsets[f][p+1] = fDof; 6926 pointMatOffsets[f][p+1] = 0; 6927 } 6928 } 6929 } 6930 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6931 newPointOffsets[f][0] = totalOffset; 6932 pointMatOffsets[f][0] = totalMatOffset; 6933 for (p = 0; p < numPoints; p++) { 6934 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6935 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6936 } 6937 totalOffset = newPointOffsets[f][numPoints]; 6938 totalMatOffset = pointMatOffsets[f][numPoints]; 6939 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6940 } 6941 } 6942 else { 6943 for (p = 0; p < numPoints; p++) { 6944 PetscInt b = points[2*p]; 6945 PetscInt bDof = 0, bSecDof; 6946 6947 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6948 if (!bSecDof) { 6949 newPointOffsets[0][p + 1] = 0; 6950 pointMatOffsets[0][p + 1] = 0; 6951 continue; 6952 } 6953 if (b >= aStart && b < aEnd) { 6954 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6955 } 6956 if (bDof) { 6957 PetscInt bOff, q, allDof = 0; 6958 6959 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6960 for (q = 0; q < bDof; q++) { 6961 PetscInt a = anchors[bOff + q], aDof; 6962 6963 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6964 allDof += aDof; 6965 } 6966 newPointOffsets[0][p+1] = allDof; 6967 pointMatOffsets[0][p+1] = bSecDof * allDof; 6968 } 6969 else { 6970 newPointOffsets[0][p+1] = bSecDof; 6971 pointMatOffsets[0][p+1] = 0; 6972 } 6973 } 6974 newPointOffsets[0][0] = 0; 6975 pointMatOffsets[0][0] = 0; 6976 for (p = 0; p < numPoints; p++) { 6977 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6978 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6979 } 6980 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6981 } 6982 6983 /* output arrays */ 6984 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6985 6986 /* get the point-to-point matrices; construct newPoints */ 6987 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6988 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6989 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6990 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6991 if (numFields) { 6992 for (p = 0, newP = 0; p < numPoints; p++) { 6993 PetscInt b = points[2*p]; 6994 PetscInt o = points[2*p+1]; 6995 PetscInt bDof = 0, bSecDof; 6996 6997 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6998 if (!bSecDof) { 6999 continue; 7000 } 7001 if (b >= aStart && b < aEnd) { 7002 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7003 } 7004 if (bDof) { 7005 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7006 7007 fStart[0] = 0; 7008 fEnd[0] = 0; 7009 for (f = 0; f < numFields; f++) { 7010 PetscInt fDof; 7011 7012 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7013 fStart[f+1] = fStart[f] + fDof; 7014 fEnd[f+1] = fStart[f+1]; 7015 } 7016 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7017 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7018 7019 fAnchorStart[0] = 0; 7020 fAnchorEnd[0] = 0; 7021 for (f = 0; f < numFields; f++) { 7022 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7023 7024 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7025 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7026 } 7027 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7028 for (q = 0; q < bDof; q++) { 7029 PetscInt a = anchors[bOff + q], aOff; 7030 7031 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7032 newPoints[2*(newP + q)] = a; 7033 newPoints[2*(newP + q) + 1] = 0; 7034 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7035 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7036 } 7037 newP += bDof; 7038 7039 if (outValues) { 7040 /* get the point-to-point submatrix */ 7041 for (f = 0; f < numFields; f++) { 7042 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7043 } 7044 } 7045 } 7046 else { 7047 newPoints[2 * newP] = b; 7048 newPoints[2 * newP + 1] = o; 7049 newP++; 7050 } 7051 } 7052 } else { 7053 for (p = 0; p < numPoints; p++) { 7054 PetscInt b = points[2*p]; 7055 PetscInt o = points[2*p+1]; 7056 PetscInt bDof = 0, bSecDof; 7057 7058 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7059 if (!bSecDof) { 7060 continue; 7061 } 7062 if (b >= aStart && b < aEnd) { 7063 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7064 } 7065 if (bDof) { 7066 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7067 7068 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7069 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7070 7071 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7072 for (q = 0; q < bDof; q++) { 7073 PetscInt a = anchors[bOff + q], aOff; 7074 7075 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7076 7077 newPoints[2*(newP + q)] = a; 7078 newPoints[2*(newP + q) + 1] = 0; 7079 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7080 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7081 } 7082 newP += bDof; 7083 7084 /* get the point-to-point submatrix */ 7085 if (outValues) { 7086 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7087 } 7088 } 7089 else { 7090 newPoints[2 * newP] = b; 7091 newPoints[2 * newP + 1] = o; 7092 newP++; 7093 } 7094 } 7095 } 7096 7097 if (outValues) { 7098 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7099 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7100 /* multiply constraints on the right */ 7101 if (numFields) { 7102 for (f = 0; f < numFields; f++) { 7103 PetscInt oldOff = offsets[f]; 7104 7105 for (p = 0; p < numPoints; p++) { 7106 PetscInt cStart = newPointOffsets[f][p]; 7107 PetscInt b = points[2 * p]; 7108 PetscInt c, r, k; 7109 PetscInt dof; 7110 7111 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7112 if (!dof) { 7113 continue; 7114 } 7115 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7116 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7117 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7118 7119 for (r = 0; r < numIndices; r++) { 7120 for (c = 0; c < nCols; c++) { 7121 for (k = 0; k < dof; k++) { 7122 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7123 } 7124 } 7125 } 7126 } 7127 else { 7128 /* copy this column as is */ 7129 for (r = 0; r < numIndices; r++) { 7130 for (c = 0; c < dof; c++) { 7131 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7132 } 7133 } 7134 } 7135 oldOff += dof; 7136 } 7137 } 7138 } 7139 else { 7140 PetscInt oldOff = 0; 7141 for (p = 0; p < numPoints; p++) { 7142 PetscInt cStart = newPointOffsets[0][p]; 7143 PetscInt b = points[2 * p]; 7144 PetscInt c, r, k; 7145 PetscInt dof; 7146 7147 PetscCall(PetscSectionGetDof(section,b,&dof)); 7148 if (!dof) { 7149 continue; 7150 } 7151 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7152 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7153 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7154 7155 for (r = 0; r < numIndices; r++) { 7156 for (c = 0; c < nCols; c++) { 7157 for (k = 0; k < dof; k++) { 7158 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7159 } 7160 } 7161 } 7162 } 7163 else { 7164 /* copy this column as is */ 7165 for (r = 0; r < numIndices; r++) { 7166 for (c = 0; c < dof; c++) { 7167 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7168 } 7169 } 7170 } 7171 oldOff += dof; 7172 } 7173 } 7174 7175 if (multiplyLeft) { 7176 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7177 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7178 /* multiply constraints transpose on the left */ 7179 if (numFields) { 7180 for (f = 0; f < numFields; f++) { 7181 PetscInt oldOff = offsets[f]; 7182 7183 for (p = 0; p < numPoints; p++) { 7184 PetscInt rStart = newPointOffsets[f][p]; 7185 PetscInt b = points[2 * p]; 7186 PetscInt c, r, k; 7187 PetscInt dof; 7188 7189 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7190 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7191 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7192 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7193 7194 for (r = 0; r < nRows; r++) { 7195 for (c = 0; c < newNumIndices; c++) { 7196 for (k = 0; k < dof; k++) { 7197 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7198 } 7199 } 7200 } 7201 } 7202 else { 7203 /* copy this row as is */ 7204 for (r = 0; r < dof; r++) { 7205 for (c = 0; c < newNumIndices; c++) { 7206 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7207 } 7208 } 7209 } 7210 oldOff += dof; 7211 } 7212 } 7213 } 7214 else { 7215 PetscInt oldOff = 0; 7216 7217 for (p = 0; p < numPoints; p++) { 7218 PetscInt rStart = newPointOffsets[0][p]; 7219 PetscInt b = points[2 * p]; 7220 PetscInt c, r, k; 7221 PetscInt dof; 7222 7223 PetscCall(PetscSectionGetDof(section,b,&dof)); 7224 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7225 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7226 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7227 7228 for (r = 0; r < nRows; r++) { 7229 for (c = 0; c < newNumIndices; c++) { 7230 for (k = 0; k < dof; k++) { 7231 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7232 } 7233 } 7234 } 7235 } 7236 else { 7237 /* copy this row as is */ 7238 for (r = 0; r < dof; r++) { 7239 for (c = 0; c < newNumIndices; c++) { 7240 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7241 } 7242 } 7243 } 7244 oldOff += dof; 7245 } 7246 } 7247 7248 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7249 } 7250 else { 7251 newValues = tmpValues; 7252 } 7253 } 7254 7255 /* clean up */ 7256 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7257 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7258 7259 if (numFields) { 7260 for (f = 0; f < numFields; f++) { 7261 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7262 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7263 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7264 } 7265 } 7266 else { 7267 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7268 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7269 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7270 } 7271 PetscCall(ISRestoreIndices(aIS,&anchors)); 7272 7273 /* output */ 7274 if (outPoints) { 7275 *outPoints = newPoints; 7276 } 7277 else { 7278 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7279 } 7280 if (outValues) { 7281 *outValues = newValues; 7282 } 7283 for (f = 0; f <= numFields; f++) { 7284 offsets[f] = newOffsets[f]; 7285 } 7286 PetscFunctionReturn(0); 7287 } 7288 7289 /*@C 7290 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7291 7292 Not collective 7293 7294 Input Parameters: 7295 + dm - The DM 7296 . section - The PetscSection describing the points (a local section) 7297 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7298 . point - The point defining the closure 7299 - useClPerm - Use the closure point permutation if available 7300 7301 Output Parameters: 7302 + numIndices - The number of dof indices in the closure of point with the input sections 7303 . indices - The dof indices 7304 . outOffsets - Array to write the field offsets into, or NULL 7305 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7306 7307 Notes: 7308 Must call DMPlexRestoreClosureIndices() to free allocated memory 7309 7310 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7311 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7312 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7313 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7314 indices (with the above semantics) are implied. 7315 7316 Level: advanced 7317 7318 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7319 @*/ 7320 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7321 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7322 { 7323 /* Closure ordering */ 7324 PetscSection clSection; 7325 IS clPoints; 7326 const PetscInt *clp; 7327 PetscInt *points; 7328 const PetscInt *clperm = NULL; 7329 /* Dof permutation and sign flips */ 7330 const PetscInt **perms[32] = {NULL}; 7331 const PetscScalar **flips[32] = {NULL}; 7332 PetscScalar *valCopy = NULL; 7333 /* Hanging node constraints */ 7334 PetscInt *pointsC = NULL; 7335 PetscScalar *valuesC = NULL; 7336 PetscInt NclC, NiC; 7337 7338 PetscInt *idx; 7339 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7340 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7341 7342 PetscFunctionBeginHot; 7343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7344 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7345 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7346 if (numIndices) PetscValidIntPointer(numIndices, 6); 7347 if (indices) PetscValidPointer(indices, 7); 7348 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7349 if (values) PetscValidPointer(values, 9); 7350 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7351 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7352 PetscCall(PetscArrayzero(offsets, 32)); 7353 /* 1) Get points in closure */ 7354 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7355 if (useClPerm) { 7356 PetscInt depth, clsize; 7357 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7358 for (clsize=0,p=0; p<Ncl; p++) { 7359 PetscInt dof; 7360 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7361 clsize += dof; 7362 } 7363 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7364 } 7365 /* 2) Get number of indices on these points and field offsets from section */ 7366 for (p = 0; p < Ncl*2; p += 2) { 7367 PetscInt dof, fdof; 7368 7369 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7370 for (f = 0; f < Nf; ++f) { 7371 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7372 offsets[f+1] += fdof; 7373 } 7374 Ni += dof; 7375 } 7376 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7377 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7378 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7379 for (f = 0; f < PetscMax(1, Nf); ++f) { 7380 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7381 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7382 /* may need to apply sign changes to the element matrix */ 7383 if (values && flips[f]) { 7384 PetscInt foffset = offsets[f]; 7385 7386 for (p = 0; p < Ncl; ++p) { 7387 PetscInt pnt = points[2*p], fdof; 7388 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7389 7390 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7391 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7392 if (flip) { 7393 PetscInt i, j, k; 7394 7395 if (!valCopy) { 7396 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7397 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7398 *values = valCopy; 7399 } 7400 for (i = 0; i < fdof; ++i) { 7401 PetscScalar fval = flip[i]; 7402 7403 for (k = 0; k < Ni; ++k) { 7404 valCopy[Ni * (foffset + i) + k] *= fval; 7405 valCopy[Ni * k + (foffset + i)] *= fval; 7406 } 7407 } 7408 } 7409 foffset += fdof; 7410 } 7411 } 7412 } 7413 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7414 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7415 if (NclC) { 7416 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7417 for (f = 0; f < PetscMax(1, Nf); ++f) { 7418 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7419 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7420 } 7421 for (f = 0; f < PetscMax(1, Nf); ++f) { 7422 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7423 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7424 } 7425 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7426 Ncl = NclC; 7427 Ni = NiC; 7428 points = pointsC; 7429 if (values) *values = valuesC; 7430 } 7431 /* 5) Calculate indices */ 7432 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7433 if (Nf) { 7434 PetscInt idxOff; 7435 PetscBool useFieldOffsets; 7436 7437 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7438 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7439 if (useFieldOffsets) { 7440 for (p = 0; p < Ncl; ++p) { 7441 const PetscInt pnt = points[p*2]; 7442 7443 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7444 } 7445 } else { 7446 for (p = 0; p < Ncl; ++p) { 7447 const PetscInt pnt = points[p*2]; 7448 7449 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7450 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7451 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7452 * global section. */ 7453 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7454 } 7455 } 7456 } else { 7457 PetscInt off = 0, idxOff; 7458 7459 for (p = 0; p < Ncl; ++p) { 7460 const PetscInt pnt = points[p*2]; 7461 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7462 7463 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7464 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7465 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7466 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7467 } 7468 } 7469 /* 6) Cleanup */ 7470 for (f = 0; f < PetscMax(1, Nf); ++f) { 7471 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7472 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7473 } 7474 if (NclC) { 7475 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7476 } else { 7477 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7478 } 7479 7480 if (numIndices) *numIndices = Ni; 7481 if (indices) *indices = idx; 7482 PetscFunctionReturn(0); 7483 } 7484 7485 /*@C 7486 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7487 7488 Not collective 7489 7490 Input Parameters: 7491 + dm - The DM 7492 . section - The PetscSection describing the points (a local section) 7493 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7494 . point - The point defining the closure 7495 - useClPerm - Use the closure point permutation if available 7496 7497 Output Parameters: 7498 + numIndices - The number of dof indices in the closure of point with the input sections 7499 . indices - The dof indices 7500 . outOffsets - Array to write the field offsets into, or NULL 7501 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7502 7503 Notes: 7504 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7505 7506 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7507 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7508 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7509 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7510 indices (with the above semantics) are implied. 7511 7512 Level: advanced 7513 7514 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7515 @*/ 7516 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7517 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7518 { 7519 PetscFunctionBegin; 7520 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7521 PetscValidPointer(indices, 7); 7522 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7523 PetscFunctionReturn(0); 7524 } 7525 7526 /*@C 7527 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7528 7529 Not collective 7530 7531 Input Parameters: 7532 + dm - The DM 7533 . section - The section describing the layout in v, or NULL to use the default section 7534 . globalSection - The section describing the layout in v, or NULL to use the default global section 7535 . A - The matrix 7536 . point - The point in the DM 7537 . values - The array of values 7538 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7539 7540 Fortran Notes: 7541 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7542 7543 Level: intermediate 7544 7545 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7546 @*/ 7547 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7548 { 7549 DM_Plex *mesh = (DM_Plex*) dm->data; 7550 PetscInt *indices; 7551 PetscInt numIndices; 7552 const PetscScalar *valuesOrig = values; 7553 PetscErrorCode ierr; 7554 7555 PetscFunctionBegin; 7556 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7557 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7558 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7559 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7560 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7561 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7562 7563 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7564 7565 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7566 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7567 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7568 if (ierr) { 7569 PetscMPIInt rank; 7570 7571 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7572 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7573 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7574 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7575 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7576 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7577 } 7578 if (mesh->printFEM > 1) { 7579 PetscInt i; 7580 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7581 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7582 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7583 } 7584 7585 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7586 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7587 PetscFunctionReturn(0); 7588 } 7589 7590 /*@C 7591 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7592 7593 Not collective 7594 7595 Input Parameters: 7596 + dmRow - The DM for the row fields 7597 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7598 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7599 . dmCol - The DM for the column fields 7600 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7601 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7602 . A - The matrix 7603 . point - The point in the DMs 7604 . values - The array of values 7605 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7606 7607 Level: intermediate 7608 7609 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7610 @*/ 7611 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7612 { 7613 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7614 PetscInt *indicesRow, *indicesCol; 7615 PetscInt numIndicesRow, numIndicesCol; 7616 const PetscScalar *valuesOrig = values; 7617 PetscErrorCode ierr; 7618 7619 PetscFunctionBegin; 7620 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7621 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7622 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7623 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7624 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7625 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7626 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7627 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7628 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7629 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7630 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7631 7632 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7633 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7634 7635 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7636 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7637 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7638 if (ierr) { 7639 PetscMPIInt rank; 7640 7641 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7642 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7643 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7644 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7645 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7646 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7647 } 7648 7649 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7650 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7651 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7652 PetscFunctionReturn(0); 7653 } 7654 7655 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7656 { 7657 DM_Plex *mesh = (DM_Plex*) dmf->data; 7658 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7659 PetscInt *cpoints = NULL; 7660 PetscInt *findices, *cindices; 7661 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7662 PetscInt foffsets[32], coffsets[32]; 7663 DMPolytopeType ct; 7664 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7665 PetscErrorCode ierr; 7666 7667 PetscFunctionBegin; 7668 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7669 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7670 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7671 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7672 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7673 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7674 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7675 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7676 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7677 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7678 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7679 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7680 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7681 PetscCall(PetscArrayzero(foffsets, 32)); 7682 PetscCall(PetscArrayzero(coffsets, 32)); 7683 /* Column indices */ 7684 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7685 maxFPoints = numCPoints; 7686 /* Compress out points not in the section */ 7687 /* TODO: Squeeze out points with 0 dof as well */ 7688 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7689 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7690 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7691 cpoints[q*2] = cpoints[p]; 7692 cpoints[q*2+1] = cpoints[p+1]; 7693 ++q; 7694 } 7695 } 7696 numCPoints = q; 7697 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7698 PetscInt fdof; 7699 7700 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7701 if (!dof) continue; 7702 for (f = 0; f < numFields; ++f) { 7703 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7704 coffsets[f+1] += fdof; 7705 } 7706 numCIndices += dof; 7707 } 7708 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7709 /* Row indices */ 7710 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7711 { 7712 DMPlexTransform tr; 7713 DMPolytopeType *rct; 7714 PetscInt *rsize, *rcone, *rornt, Nt; 7715 7716 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7717 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7718 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7719 numSubcells = rsize[Nt-1]; 7720 PetscCall(DMPlexTransformDestroy(&tr)); 7721 } 7722 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7723 for (r = 0, q = 0; r < numSubcells; ++r) { 7724 /* TODO Map from coarse to fine cells */ 7725 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7726 /* Compress out points not in the section */ 7727 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7728 for (p = 0; p < numFPoints*2; p += 2) { 7729 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7730 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7731 if (!dof) continue; 7732 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7733 if (s < q) continue; 7734 ftotpoints[q*2] = fpoints[p]; 7735 ftotpoints[q*2+1] = fpoints[p+1]; 7736 ++q; 7737 } 7738 } 7739 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7740 } 7741 numFPoints = q; 7742 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7743 PetscInt fdof; 7744 7745 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7746 if (!dof) continue; 7747 for (f = 0; f < numFields; ++f) { 7748 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7749 foffsets[f+1] += fdof; 7750 } 7751 numFIndices += dof; 7752 } 7753 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7754 7755 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7756 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7757 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7758 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7759 if (numFields) { 7760 const PetscInt **permsF[32] = {NULL}; 7761 const PetscInt **permsC[32] = {NULL}; 7762 7763 for (f = 0; f < numFields; f++) { 7764 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7765 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7766 } 7767 for (p = 0; p < numFPoints; p++) { 7768 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7769 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7770 } 7771 for (p = 0; p < numCPoints; p++) { 7772 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7773 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7774 } 7775 for (f = 0; f < numFields; f++) { 7776 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7777 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7778 } 7779 } else { 7780 const PetscInt **permsF = NULL; 7781 const PetscInt **permsC = NULL; 7782 7783 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7784 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7785 for (p = 0, off = 0; p < numFPoints; p++) { 7786 const PetscInt *perm = permsF ? permsF[p] : NULL; 7787 7788 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7789 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7790 } 7791 for (p = 0, off = 0; p < numCPoints; p++) { 7792 const PetscInt *perm = permsC ? permsC[p] : NULL; 7793 7794 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7795 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7796 } 7797 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7798 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7799 } 7800 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7801 /* TODO: flips */ 7802 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7803 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7804 if (ierr) { 7805 PetscMPIInt rank; 7806 7807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7808 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7809 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7810 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7811 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7812 } 7813 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7814 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7815 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7816 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7817 PetscFunctionReturn(0); 7818 } 7819 7820 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7821 { 7822 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7823 PetscInt *cpoints = NULL; 7824 PetscInt foffsets[32], coffsets[32]; 7825 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7826 DMPolytopeType ct; 7827 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7828 7829 PetscFunctionBegin; 7830 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7831 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7832 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7833 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7834 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7835 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7836 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7837 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7838 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7839 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7840 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7841 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7842 PetscCall(PetscArrayzero(foffsets, 32)); 7843 PetscCall(PetscArrayzero(coffsets, 32)); 7844 /* Column indices */ 7845 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7846 maxFPoints = numCPoints; 7847 /* Compress out points not in the section */ 7848 /* TODO: Squeeze out points with 0 dof as well */ 7849 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7850 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7851 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7852 cpoints[q*2] = cpoints[p]; 7853 cpoints[q*2+1] = cpoints[p+1]; 7854 ++q; 7855 } 7856 } 7857 numCPoints = q; 7858 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7859 PetscInt fdof; 7860 7861 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7862 if (!dof) continue; 7863 for (f = 0; f < numFields; ++f) { 7864 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7865 coffsets[f+1] += fdof; 7866 } 7867 numCIndices += dof; 7868 } 7869 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7870 /* Row indices */ 7871 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7872 { 7873 DMPlexTransform tr; 7874 DMPolytopeType *rct; 7875 PetscInt *rsize, *rcone, *rornt, Nt; 7876 7877 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7878 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7879 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7880 numSubcells = rsize[Nt-1]; 7881 PetscCall(DMPlexTransformDestroy(&tr)); 7882 } 7883 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7884 for (r = 0, q = 0; r < numSubcells; ++r) { 7885 /* TODO Map from coarse to fine cells */ 7886 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7887 /* Compress out points not in the section */ 7888 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7889 for (p = 0; p < numFPoints*2; p += 2) { 7890 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7891 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7892 if (!dof) continue; 7893 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7894 if (s < q) continue; 7895 ftotpoints[q*2] = fpoints[p]; 7896 ftotpoints[q*2+1] = fpoints[p+1]; 7897 ++q; 7898 } 7899 } 7900 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7901 } 7902 numFPoints = q; 7903 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7904 PetscInt fdof; 7905 7906 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7907 if (!dof) continue; 7908 for (f = 0; f < numFields; ++f) { 7909 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7910 foffsets[f+1] += fdof; 7911 } 7912 numFIndices += dof; 7913 } 7914 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7915 7916 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7917 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7918 if (numFields) { 7919 const PetscInt **permsF[32] = {NULL}; 7920 const PetscInt **permsC[32] = {NULL}; 7921 7922 for (f = 0; f < numFields; f++) { 7923 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7924 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7925 } 7926 for (p = 0; p < numFPoints; p++) { 7927 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7928 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7929 } 7930 for (p = 0; p < numCPoints; p++) { 7931 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7932 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7933 } 7934 for (f = 0; f < numFields; f++) { 7935 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7936 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7937 } 7938 } else { 7939 const PetscInt **permsF = NULL; 7940 const PetscInt **permsC = NULL; 7941 7942 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7943 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7944 for (p = 0, off = 0; p < numFPoints; p++) { 7945 const PetscInt *perm = permsF ? permsF[p] : NULL; 7946 7947 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7948 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7949 } 7950 for (p = 0, off = 0; p < numCPoints; p++) { 7951 const PetscInt *perm = permsC ? permsC[p] : NULL; 7952 7953 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7954 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7955 } 7956 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7957 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7958 } 7959 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7960 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7961 PetscFunctionReturn(0); 7962 } 7963 7964 /*@C 7965 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7966 7967 Input Parameter: 7968 . dm - The DMPlex object 7969 7970 Output Parameter: 7971 . cellHeight - The height of a cell 7972 7973 Level: developer 7974 7975 .seealso `DMPlexSetVTKCellHeight()` 7976 @*/ 7977 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7978 { 7979 DM_Plex *mesh = (DM_Plex*) dm->data; 7980 7981 PetscFunctionBegin; 7982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7983 PetscValidIntPointer(cellHeight, 2); 7984 *cellHeight = mesh->vtkCellHeight; 7985 PetscFunctionReturn(0); 7986 } 7987 7988 /*@C 7989 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7990 7991 Input Parameters: 7992 + dm - The DMPlex object 7993 - cellHeight - The height of a cell 7994 7995 Level: developer 7996 7997 .seealso `DMPlexGetVTKCellHeight()` 7998 @*/ 7999 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8000 { 8001 DM_Plex *mesh = (DM_Plex*) dm->data; 8002 8003 PetscFunctionBegin; 8004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8005 mesh->vtkCellHeight = cellHeight; 8006 PetscFunctionReturn(0); 8007 } 8008 8009 /*@ 8010 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8011 8012 Input Parameter: 8013 . dm - The DMPlex object 8014 8015 Output Parameters: 8016 + gcStart - The first ghost cell, or NULL 8017 - gcEnd - The upper bound on ghost cells, or NULL 8018 8019 Level: advanced 8020 8021 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8022 @*/ 8023 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8024 { 8025 DMLabel ctLabel; 8026 8027 PetscFunctionBegin; 8028 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8029 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8030 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8031 // Reset label for fast lookup 8032 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8033 PetscFunctionReturn(0); 8034 } 8035 8036 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8037 { 8038 PetscSection section, globalSection; 8039 PetscInt *numbers, p; 8040 8041 PetscFunctionBegin; 8042 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8043 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8044 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8045 for (p = pStart; p < pEnd; ++p) { 8046 PetscCall(PetscSectionSetDof(section, p, 1)); 8047 } 8048 PetscCall(PetscSectionSetUp(section)); 8049 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8050 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8051 for (p = pStart; p < pEnd; ++p) { 8052 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8053 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8054 else numbers[p-pStart] += shift; 8055 } 8056 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8057 if (globalSize) { 8058 PetscLayout layout; 8059 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8060 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8061 PetscCall(PetscLayoutDestroy(&layout)); 8062 } 8063 PetscCall(PetscSectionDestroy(§ion)); 8064 PetscCall(PetscSectionDestroy(&globalSection)); 8065 PetscFunctionReturn(0); 8066 } 8067 8068 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8069 { 8070 PetscInt cellHeight, cStart, cEnd; 8071 8072 PetscFunctionBegin; 8073 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8074 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8075 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8076 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8077 PetscFunctionReturn(0); 8078 } 8079 8080 /*@ 8081 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8082 8083 Input Parameter: 8084 . dm - The DMPlex object 8085 8086 Output Parameter: 8087 . globalCellNumbers - Global cell numbers for all cells on this process 8088 8089 Level: developer 8090 8091 .seealso `DMPlexGetVertexNumbering()` 8092 @*/ 8093 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8094 { 8095 DM_Plex *mesh = (DM_Plex*) dm->data; 8096 8097 PetscFunctionBegin; 8098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8099 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8100 *globalCellNumbers = mesh->globalCellNumbers; 8101 PetscFunctionReturn(0); 8102 } 8103 8104 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8105 { 8106 PetscInt vStart, vEnd; 8107 8108 PetscFunctionBegin; 8109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8111 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8112 PetscFunctionReturn(0); 8113 } 8114 8115 /*@ 8116 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8117 8118 Input Parameter: 8119 . dm - The DMPlex object 8120 8121 Output Parameter: 8122 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8123 8124 Level: developer 8125 8126 .seealso `DMPlexGetCellNumbering()` 8127 @*/ 8128 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8129 { 8130 DM_Plex *mesh = (DM_Plex*) dm->data; 8131 8132 PetscFunctionBegin; 8133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8134 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8135 *globalVertexNumbers = mesh->globalVertexNumbers; 8136 PetscFunctionReturn(0); 8137 } 8138 8139 /*@ 8140 DMPlexCreatePointNumbering - Create a global numbering for all points. 8141 8142 Collective on dm 8143 8144 Input Parameter: 8145 . dm - The DMPlex object 8146 8147 Output Parameter: 8148 . globalPointNumbers - Global numbers for all points on this process 8149 8150 Notes: 8151 8152 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8153 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8154 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8155 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8156 8157 The partitioned mesh is 8158 ``` 8159 (2)--0--(3)--1--(4) (1)--0--(2) 8160 ``` 8161 and its global numbering is 8162 ``` 8163 (3)--0--(4)--1--(5)--2--(6) 8164 ``` 8165 Then the global numbering is provided as 8166 ``` 8167 [0] Number of indices in set 5 8168 [0] 0 0 8169 [0] 1 1 8170 [0] 2 3 8171 [0] 3 4 8172 [0] 4 -6 8173 [1] Number of indices in set 3 8174 [1] 0 2 8175 [1] 1 5 8176 [1] 2 6 8177 ``` 8178 8179 Level: developer 8180 8181 .seealso `DMPlexGetCellNumbering()` 8182 @*/ 8183 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8184 { 8185 IS nums[4]; 8186 PetscInt depths[4], gdepths[4], starts[4]; 8187 PetscInt depth, d, shift = 0; 8188 8189 PetscFunctionBegin; 8190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8191 PetscCall(DMPlexGetDepth(dm, &depth)); 8192 /* For unstratified meshes use dim instead of depth */ 8193 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8194 for (d = 0; d <= depth; ++d) { 8195 PetscInt end; 8196 8197 depths[d] = depth-d; 8198 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8199 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8200 } 8201 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8202 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8203 for (d = 0; d <= depth; ++d) { 8204 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]); 8205 } 8206 for (d = 0; d <= depth; ++d) { 8207 PetscInt pStart, pEnd, gsize; 8208 8209 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8210 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8211 shift += gsize; 8212 } 8213 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8214 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8215 PetscFunctionReturn(0); 8216 } 8217 8218 /*@ 8219 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8220 8221 Input Parameter: 8222 . dm - The DMPlex object 8223 8224 Output Parameter: 8225 . ranks - The rank field 8226 8227 Options Database Keys: 8228 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8229 8230 Level: intermediate 8231 8232 .seealso: `DMView()` 8233 @*/ 8234 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8235 { 8236 DM rdm; 8237 PetscFE fe; 8238 PetscScalar *r; 8239 PetscMPIInt rank; 8240 DMPolytopeType ct; 8241 PetscInt dim, cStart, cEnd, c; 8242 PetscBool simplex; 8243 8244 PetscFunctionBeginUser; 8245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8246 PetscValidPointer(ranks, 2); 8247 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8248 PetscCall(DMClone(dm, &rdm)); 8249 PetscCall(DMGetDimension(rdm, &dim)); 8250 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8251 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8252 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8253 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8254 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8255 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8256 PetscCall(PetscFEDestroy(&fe)); 8257 PetscCall(DMCreateDS(rdm)); 8258 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8259 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8260 PetscCall(VecGetArray(*ranks, &r)); 8261 for (c = cStart; c < cEnd; ++c) { 8262 PetscScalar *lr; 8263 8264 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8265 if (lr) *lr = rank; 8266 } 8267 PetscCall(VecRestoreArray(*ranks, &r)); 8268 PetscCall(DMDestroy(&rdm)); 8269 PetscFunctionReturn(0); 8270 } 8271 8272 /*@ 8273 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8274 8275 Input Parameters: 8276 + dm - The DMPlex 8277 - label - The DMLabel 8278 8279 Output Parameter: 8280 . val - The label value field 8281 8282 Options Database Keys: 8283 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8284 8285 Level: intermediate 8286 8287 .seealso: `DMView()` 8288 @*/ 8289 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8290 { 8291 DM rdm; 8292 PetscFE fe; 8293 PetscScalar *v; 8294 PetscInt dim, cStart, cEnd, c; 8295 8296 PetscFunctionBeginUser; 8297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8298 PetscValidPointer(label, 2); 8299 PetscValidPointer(val, 3); 8300 PetscCall(DMClone(dm, &rdm)); 8301 PetscCall(DMGetDimension(rdm, &dim)); 8302 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8303 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8304 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8305 PetscCall(PetscFEDestroy(&fe)); 8306 PetscCall(DMCreateDS(rdm)); 8307 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8308 PetscCall(DMCreateGlobalVector(rdm, val)); 8309 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8310 PetscCall(VecGetArray(*val, &v)); 8311 for (c = cStart; c < cEnd; ++c) { 8312 PetscScalar *lv; 8313 PetscInt cval; 8314 8315 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8316 PetscCall(DMLabelGetValue(label, c, &cval)); 8317 *lv = cval; 8318 } 8319 PetscCall(VecRestoreArray(*val, &v)); 8320 PetscCall(DMDestroy(&rdm)); 8321 PetscFunctionReturn(0); 8322 } 8323 8324 /*@ 8325 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8326 8327 Input Parameter: 8328 . dm - The DMPlex object 8329 8330 Notes: 8331 This is a useful diagnostic when creating meshes programmatically. 8332 8333 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8334 8335 Level: developer 8336 8337 .seealso: `DMCreate()`, `DMSetFromOptions()` 8338 @*/ 8339 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8340 { 8341 PetscSection coneSection, supportSection; 8342 const PetscInt *cone, *support; 8343 PetscInt coneSize, c, supportSize, s; 8344 PetscInt pStart, pEnd, p, pp, csize, ssize; 8345 PetscBool storagecheck = PETSC_TRUE; 8346 8347 PetscFunctionBegin; 8348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8349 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8350 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8351 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8352 /* Check that point p is found in the support of its cone points, and vice versa */ 8353 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8354 for (p = pStart; p < pEnd; ++p) { 8355 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8356 PetscCall(DMPlexGetCone(dm, p, &cone)); 8357 for (c = 0; c < coneSize; ++c) { 8358 PetscBool dup = PETSC_FALSE; 8359 PetscInt d; 8360 for (d = c-1; d >= 0; --d) { 8361 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8362 } 8363 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8364 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8365 for (s = 0; s < supportSize; ++s) { 8366 if (support[s] == p) break; 8367 } 8368 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8369 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8370 for (s = 0; s < coneSize; ++s) { 8371 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8372 } 8373 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8374 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8375 for (s = 0; s < supportSize; ++s) { 8376 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8377 } 8378 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8379 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]); 8380 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8381 } 8382 } 8383 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8384 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8385 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8386 PetscCall(DMPlexGetSupport(dm, p, &support)); 8387 for (s = 0; s < supportSize; ++s) { 8388 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8389 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8390 for (c = 0; c < coneSize; ++c) { 8391 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8392 if (cone[c] != pp) { c = 0; break; } 8393 if (cone[c] == p) break; 8394 } 8395 if (c >= coneSize) { 8396 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8397 for (c = 0; c < supportSize; ++c) { 8398 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8399 } 8400 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8401 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8402 for (c = 0; c < coneSize; ++c) { 8403 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8404 } 8405 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8406 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8407 } 8408 } 8409 } 8410 if (storagecheck) { 8411 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8412 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8413 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8414 } 8415 PetscFunctionReturn(0); 8416 } 8417 8418 /* 8419 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. 8420 */ 8421 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8422 { 8423 DMPolytopeType cct; 8424 PetscInt ptpoints[4]; 8425 const PetscInt *cone, *ccone, *ptcone; 8426 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8427 8428 PetscFunctionBegin; 8429 *unsplit = 0; 8430 switch (ct) { 8431 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8432 ptpoints[npt++] = c; 8433 break; 8434 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8435 PetscCall(DMPlexGetCone(dm, c, &cone)); 8436 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8437 for (cp = 0; cp < coneSize; ++cp) { 8438 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8439 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8440 } 8441 break; 8442 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8443 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8444 PetscCall(DMPlexGetCone(dm, c, &cone)); 8445 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8446 for (cp = 0; cp < coneSize; ++cp) { 8447 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8448 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8449 for (ccp = 0; ccp < cconeSize; ++ccp) { 8450 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8451 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8452 PetscInt p; 8453 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8454 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8455 } 8456 } 8457 } 8458 break; 8459 default: break; 8460 } 8461 for (pt = 0; pt < npt; ++pt) { 8462 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8463 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8464 } 8465 PetscFunctionReturn(0); 8466 } 8467 8468 /*@ 8469 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8470 8471 Input Parameters: 8472 + dm - The DMPlex object 8473 - cellHeight - Normally 0 8474 8475 Notes: 8476 This is a useful diagnostic when creating meshes programmatically. 8477 Currently applicable only to homogeneous simplex or tensor meshes. 8478 8479 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8480 8481 Level: developer 8482 8483 .seealso: `DMCreate()`, `DMSetFromOptions()` 8484 @*/ 8485 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8486 { 8487 DMPlexInterpolatedFlag interp; 8488 DMPolytopeType ct; 8489 PetscInt vStart, vEnd, cStart, cEnd, c; 8490 8491 PetscFunctionBegin; 8492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8493 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8494 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8495 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8496 for (c = cStart; c < cEnd; ++c) { 8497 PetscInt *closure = NULL; 8498 PetscInt coneSize, closureSize, cl, Nv = 0; 8499 8500 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8501 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8502 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8503 if (interp == DMPLEX_INTERPOLATED_FULL) { 8504 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8505 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)); 8506 } 8507 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8508 for (cl = 0; cl < closureSize*2; cl += 2) { 8509 const PetscInt p = closure[cl]; 8510 if ((p >= vStart) && (p < vEnd)) ++Nv; 8511 } 8512 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8513 /* Special Case: Tensor faces with identified vertices */ 8514 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8515 PetscInt unsplit; 8516 8517 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8518 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8519 } 8520 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)); 8521 } 8522 PetscFunctionReturn(0); 8523 } 8524 8525 /*@ 8526 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8527 8528 Collective 8529 8530 Input Parameters: 8531 + dm - The DMPlex object 8532 - cellHeight - Normally 0 8533 8534 Notes: 8535 This is a useful diagnostic when creating meshes programmatically. 8536 This routine is only relevant for meshes that are fully interpolated across all ranks. 8537 It will error out if a partially interpolated mesh is given on some rank. 8538 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8539 8540 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8541 8542 Level: developer 8543 8544 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8545 @*/ 8546 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8547 { 8548 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8549 DMPlexInterpolatedFlag interpEnum; 8550 8551 PetscFunctionBegin; 8552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8553 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8554 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8555 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8556 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8557 PetscFunctionReturn(0); 8558 } 8559 8560 PetscCall(DMGetDimension(dm, &dim)); 8561 PetscCall(DMPlexGetDepth(dm, &depth)); 8562 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8563 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8564 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8565 for (c = cStart; c < cEnd; ++c) { 8566 const PetscInt *cone, *ornt, *faceSizes, *faces; 8567 const DMPolytopeType *faceTypes; 8568 DMPolytopeType ct; 8569 PetscInt numFaces, coneSize, f; 8570 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8571 8572 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8573 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8574 if (unsplit) continue; 8575 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8576 PetscCall(DMPlexGetCone(dm, c, &cone)); 8577 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8578 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8579 for (cl = 0; cl < closureSize*2; cl += 2) { 8580 const PetscInt p = closure[cl]; 8581 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8582 } 8583 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8584 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); 8585 for (f = 0; f < numFaces; ++f) { 8586 DMPolytopeType fct; 8587 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8588 8589 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8590 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8591 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8592 const PetscInt p = fclosure[cl]; 8593 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8594 } 8595 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]); 8596 for (v = 0; v < fnumCorners; ++v) { 8597 if (fclosure[v] != faces[fOff+v]) { 8598 PetscInt v1; 8599 8600 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8601 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8602 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8603 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8604 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8605 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]); 8606 } 8607 } 8608 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8609 fOff += faceSizes[f]; 8610 } 8611 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8612 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8613 } 8614 } 8615 PetscFunctionReturn(0); 8616 } 8617 8618 /*@ 8619 DMPlexCheckGeometry - Check the geometry of mesh cells 8620 8621 Input Parameter: 8622 . dm - The DMPlex object 8623 8624 Notes: 8625 This is a useful diagnostic when creating meshes programmatically. 8626 8627 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8628 8629 Level: developer 8630 8631 .seealso: `DMCreate()`, `DMSetFromOptions()` 8632 @*/ 8633 PetscErrorCode DMPlexCheckGeometry(DM dm) 8634 { 8635 Vec coordinates; 8636 PetscReal detJ, J[9], refVol = 1.0; 8637 PetscReal vol; 8638 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8639 8640 PetscFunctionBegin; 8641 PetscCall(DMGetDimension(dm, &dim)); 8642 PetscCall(DMGetCoordinateDim(dm, &dE)); 8643 if (dim != dE) PetscFunctionReturn(0); 8644 PetscCall(DMPlexGetDepth(dm, &depth)); 8645 for (d = 0; d < dim; ++d) refVol *= 2.0; 8646 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8647 /* Make sure local coordinates are created, because that step is collective */ 8648 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8649 for (c = cStart; c < cEnd; ++c) { 8650 DMPolytopeType ct; 8651 PetscInt unsplit; 8652 PetscBool ignoreZeroVol = PETSC_FALSE; 8653 8654 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8655 switch (ct) { 8656 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8657 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8658 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8659 ignoreZeroVol = PETSC_TRUE; break; 8660 default: break; 8661 } 8662 switch (ct) { 8663 case DM_POLYTOPE_TRI_PRISM: 8664 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8665 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8666 case DM_POLYTOPE_PYRAMID: 8667 continue; 8668 default: break; 8669 } 8670 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8671 if (unsplit) continue; 8672 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8673 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); 8674 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8675 /* This should work with periodicity since DG coordinates should be used */ 8676 if (depth > 1) { 8677 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8678 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); 8679 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8680 } 8681 } 8682 PetscFunctionReturn(0); 8683 } 8684 8685 /*@ 8686 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8687 8688 Collective 8689 8690 Input Parameters: 8691 + dm - The DMPlex object 8692 - pointSF - The Point SF, or NULL for Point SF attached to DM 8693 8694 Notes: 8695 This is mainly intended for debugging/testing purposes. 8696 8697 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8698 8699 Level: developer 8700 8701 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8702 @*/ 8703 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8704 { 8705 PetscInt l, nleaves, nroots, overlap; 8706 const PetscInt *locals; 8707 const PetscSFNode *remotes; 8708 PetscBool distributed; 8709 MPI_Comm comm; 8710 PetscMPIInt rank; 8711 8712 PetscFunctionBegin; 8713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8714 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8715 else pointSF = dm->sf; 8716 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8717 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8718 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8719 { 8720 PetscMPIInt mpiFlag; 8721 8722 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8723 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8724 } 8725 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8726 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8727 if (!distributed) { 8728 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); 8729 PetscFunctionReturn(0); 8730 } 8731 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); 8732 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8733 8734 /* Check SF graph is compatible with DMPlex chart */ 8735 { 8736 PetscInt pStart, pEnd, maxLeaf; 8737 8738 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8739 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8740 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8741 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8742 } 8743 8744 /* Check Point SF has no local points referenced */ 8745 for (l = 0; l < nleaves; l++) { 8746 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); 8747 } 8748 8749 /* Check there are no cells in interface */ 8750 if (!overlap) { 8751 PetscInt cellHeight, cStart, cEnd; 8752 8753 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8754 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8755 for (l = 0; l < nleaves; ++l) { 8756 const PetscInt point = locals ? locals[l] : l; 8757 8758 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8759 } 8760 } 8761 8762 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8763 { 8764 const PetscInt *rootdegree; 8765 8766 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8767 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8768 for (l = 0; l < nleaves; ++l) { 8769 const PetscInt point = locals ? locals[l] : l; 8770 const PetscInt *cone; 8771 PetscInt coneSize, c, idx; 8772 8773 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8774 PetscCall(DMPlexGetCone(dm, point, &cone)); 8775 for (c = 0; c < coneSize; ++c) { 8776 if (!rootdegree[cone[c]]) { 8777 if (locals) { 8778 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8779 } else { 8780 idx = (cone[c] < nleaves) ? cone[c] : -1; 8781 } 8782 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8783 } 8784 } 8785 } 8786 } 8787 PetscFunctionReturn(0); 8788 } 8789 8790 /*@ 8791 DMPlexCheck - Perform various checks of Plex sanity 8792 8793 Input Parameter: 8794 . dm - The DMPlex object 8795 8796 Notes: 8797 This is a useful diagnostic when creating meshes programmatically. 8798 8799 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8800 8801 Currently does not include DMPlexCheckCellShape(). 8802 8803 Level: developer 8804 8805 .seealso: DMCreate(), DMSetFromOptions() 8806 @*/ 8807 PetscErrorCode DMPlexCheck(DM dm) 8808 { 8809 PetscInt cellHeight; 8810 8811 PetscFunctionBegin; 8812 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8813 PetscCall(DMPlexCheckSymmetry(dm)); 8814 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8815 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8816 PetscCall(DMPlexCheckGeometry(dm)); 8817 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8818 PetscCall(DMPlexCheckInterfaceCones(dm)); 8819 PetscFunctionReturn(0); 8820 } 8821 8822 typedef struct cell_stats 8823 { 8824 PetscReal min, max, sum, squaresum; 8825 PetscInt count; 8826 } cell_stats_t; 8827 8828 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8829 { 8830 PetscInt i, N = *len; 8831 8832 for (i = 0; i < N; i++) { 8833 cell_stats_t *A = (cell_stats_t *) a; 8834 cell_stats_t *B = (cell_stats_t *) b; 8835 8836 B->min = PetscMin(A->min,B->min); 8837 B->max = PetscMax(A->max,B->max); 8838 B->sum += A->sum; 8839 B->squaresum += A->squaresum; 8840 B->count += A->count; 8841 } 8842 } 8843 8844 /*@ 8845 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8846 8847 Collective on dm 8848 8849 Input Parameters: 8850 + dm - The DMPlex object 8851 . output - If true, statistics will be displayed on stdout 8852 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8853 8854 Notes: 8855 This is mainly intended for debugging/testing purposes. 8856 8857 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8858 8859 Level: developer 8860 8861 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8862 @*/ 8863 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8864 { 8865 DM dmCoarse; 8866 cell_stats_t stats, globalStats; 8867 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8868 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8869 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8870 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8871 PetscMPIInt rank,size; 8872 8873 PetscFunctionBegin; 8874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8875 stats.min = PETSC_MAX_REAL; 8876 stats.max = PETSC_MIN_REAL; 8877 stats.sum = stats.squaresum = 0.; 8878 stats.count = 0; 8879 8880 PetscCallMPI(MPI_Comm_size(comm, &size)); 8881 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8882 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8883 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8884 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8885 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8886 for (c = cStart; c < cEnd; c++) { 8887 PetscInt i; 8888 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8889 8890 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8891 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8892 for (i = 0; i < PetscSqr(cdim); ++i) { 8893 frobJ += J[i] * J[i]; 8894 frobInvJ += invJ[i] * invJ[i]; 8895 } 8896 cond2 = frobJ * frobInvJ; 8897 cond = PetscSqrtReal(cond2); 8898 8899 stats.min = PetscMin(stats.min,cond); 8900 stats.max = PetscMax(stats.max,cond); 8901 stats.sum += cond; 8902 stats.squaresum += cond2; 8903 stats.count++; 8904 if (output && cond > limit) { 8905 PetscSection coordSection; 8906 Vec coordsLocal; 8907 PetscScalar *coords = NULL; 8908 PetscInt Nv, d, clSize, cl, *closure = NULL; 8909 8910 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8911 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8912 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8913 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8914 for (i = 0; i < Nv/cdim; ++i) { 8915 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8916 for (d = 0; d < cdim; ++d) { 8917 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8918 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8919 } 8920 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8921 } 8922 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8923 for (cl = 0; cl < clSize*2; cl += 2) { 8924 const PetscInt edge = closure[cl]; 8925 8926 if ((edge >= eStart) && (edge < eEnd)) { 8927 PetscReal len; 8928 8929 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8930 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8931 } 8932 } 8933 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8934 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8935 } 8936 } 8937 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8938 8939 if (size > 1) { 8940 PetscMPIInt blockLengths[2] = {4,1}; 8941 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8942 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8943 MPI_Op statReduce; 8944 8945 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8946 PetscCallMPI(MPI_Type_commit(&statType)); 8947 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8948 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8949 PetscCallMPI(MPI_Op_free(&statReduce)); 8950 PetscCallMPI(MPI_Type_free(&statType)); 8951 } else { 8952 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8953 } 8954 if (rank == 0) { 8955 count = globalStats.count; 8956 min = globalStats.min; 8957 max = globalStats.max; 8958 mean = globalStats.sum / globalStats.count; 8959 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8960 } 8961 8962 if (output) { 8963 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)); 8964 } 8965 PetscCall(PetscFree2(J,invJ)); 8966 8967 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8968 if (dmCoarse) { 8969 PetscBool isplex; 8970 8971 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8972 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8973 } 8974 PetscFunctionReturn(0); 8975 } 8976 8977 /*@ 8978 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8979 orthogonal quality below given tolerance. 8980 8981 Collective on dm 8982 8983 Input Parameters: 8984 + dm - The DMPlex object 8985 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8986 - atol - [0, 1] Absolute tolerance for tagging cells. 8987 8988 Output Parameters: 8989 + OrthQual - Vec containing orthogonal quality per cell 8990 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8991 8992 Options Database Keys: 8993 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8994 supported. 8995 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8996 8997 Notes: 8998 Orthogonal quality is given by the following formula: 8999 9000 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 9001 9002 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 9003 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9004 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9005 calculating the cosine of the angle between these vectors. 9006 9007 Orthogonal quality ranges from 1 (best) to 0 (worst). 9008 9009 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 9010 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9011 9012 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9013 9014 Level: intermediate 9015 9016 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9017 @*/ 9018 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9019 { 9020 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9021 PetscInt *idx; 9022 PetscScalar *oqVals; 9023 const PetscScalar *cellGeomArr, *faceGeomArr; 9024 PetscReal *ci, *fi, *Ai; 9025 MPI_Comm comm; 9026 Vec cellgeom, facegeom; 9027 DM dmFace, dmCell; 9028 IS glob; 9029 ISLocalToGlobalMapping ltog; 9030 PetscViewer vwr; 9031 9032 PetscFunctionBegin; 9033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9034 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 9035 PetscValidPointer(OrthQual, 4); 9036 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 9037 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9038 PetscCall(DMGetDimension(dm, &nc)); 9039 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9040 { 9041 DMPlexInterpolatedFlag interpFlag; 9042 9043 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9044 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9045 PetscMPIInt rank; 9046 9047 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9048 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9049 } 9050 } 9051 if (OrthQualLabel) { 9052 PetscValidPointer(OrthQualLabel, 5); 9053 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9054 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9055 } else {*OrthQualLabel = NULL;} 9056 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9057 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9058 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9059 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9060 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9061 PetscCall(VecCreate(comm, OrthQual)); 9062 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9063 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9064 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9065 PetscCall(VecSetUp(*OrthQual)); 9066 PetscCall(ISDestroy(&glob)); 9067 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9068 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9069 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9070 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9071 PetscCall(VecGetDM(cellgeom, &dmCell)); 9072 PetscCall(VecGetDM(facegeom, &dmFace)); 9073 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9074 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9075 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9076 PetscInt cellarr[2], *adj = NULL; 9077 PetscScalar *cArr, *fArr; 9078 PetscReal minvalc = 1.0, minvalf = 1.0; 9079 PetscFVCellGeom *cg; 9080 9081 idx[cellIter] = cell-cStart; 9082 cellarr[0] = cell; 9083 /* Make indexing into cellGeom easier */ 9084 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9085 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9086 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9087 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9088 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9089 PetscInt i; 9090 const PetscInt neigh = adj[cellneigh]; 9091 PetscReal normci = 0, normfi = 0, normai = 0; 9092 PetscFVCellGeom *cgneigh; 9093 PetscFVFaceGeom *fg; 9094 9095 /* Don't count ourselves in the neighbor list */ 9096 if (neigh == cell) continue; 9097 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9098 cellarr[1] = neigh; 9099 { 9100 PetscInt numcovpts; 9101 const PetscInt *covpts; 9102 9103 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9104 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9105 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9106 } 9107 9108 /* Compute c_i, f_i and their norms */ 9109 for (i = 0; i < nc; i++) { 9110 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9111 fi[i] = fg->centroid[i] - cg->centroid[i]; 9112 Ai[i] = fg->normal[i]; 9113 normci += PetscPowReal(ci[i], 2); 9114 normfi += PetscPowReal(fi[i], 2); 9115 normai += PetscPowReal(Ai[i], 2); 9116 } 9117 normci = PetscSqrtReal(normci); 9118 normfi = PetscSqrtReal(normfi); 9119 normai = PetscSqrtReal(normai); 9120 9121 /* Normalize and compute for each face-cell-normal pair */ 9122 for (i = 0; i < nc; i++) { 9123 ci[i] = ci[i]/normci; 9124 fi[i] = fi[i]/normfi; 9125 Ai[i] = Ai[i]/normai; 9126 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9127 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9128 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9129 } 9130 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9131 minvalc = PetscRealPart(cArr[cellneighiter]); 9132 } 9133 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9134 minvalf = PetscRealPart(fArr[cellneighiter]); 9135 } 9136 } 9137 PetscCall(PetscFree(adj)); 9138 PetscCall(PetscFree2(cArr, fArr)); 9139 /* Defer to cell if they're equal */ 9140 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9141 if (OrthQualLabel) { 9142 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9143 } 9144 } 9145 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9146 PetscCall(VecAssemblyBegin(*OrthQual)); 9147 PetscCall(VecAssemblyEnd(*OrthQual)); 9148 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9149 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9150 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9151 if (OrthQualLabel) { 9152 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9153 } 9154 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9155 PetscCall(PetscViewerDestroy(&vwr)); 9156 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9157 PetscFunctionReturn(0); 9158 } 9159 9160 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9161 * interpolator construction */ 9162 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9163 { 9164 PetscSection section, newSection, gsection; 9165 PetscSF sf; 9166 PetscBool hasConstraints, ghasConstraints; 9167 9168 PetscFunctionBegin; 9169 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9170 PetscValidPointer(odm,2); 9171 PetscCall(DMGetLocalSection(dm, §ion)); 9172 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9173 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9174 if (!ghasConstraints) { 9175 PetscCall(PetscObjectReference((PetscObject)dm)); 9176 *odm = dm; 9177 PetscFunctionReturn(0); 9178 } 9179 PetscCall(DMClone(dm, odm)); 9180 PetscCall(DMCopyFields(dm, *odm)); 9181 PetscCall(DMGetLocalSection(*odm, &newSection)); 9182 PetscCall(DMGetPointSF(*odm, &sf)); 9183 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9184 PetscCall(DMSetGlobalSection(*odm, gsection)); 9185 PetscCall(PetscSectionDestroy(&gsection)); 9186 PetscFunctionReturn(0); 9187 } 9188 9189 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9190 { 9191 DM dmco, dmfo; 9192 Mat interpo; 9193 Vec rscale; 9194 Vec cglobalo, clocal; 9195 Vec fglobal, fglobalo, flocal; 9196 PetscBool regular; 9197 9198 PetscFunctionBegin; 9199 PetscCall(DMGetFullDM(dmc, &dmco)); 9200 PetscCall(DMGetFullDM(dmf, &dmfo)); 9201 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9202 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9203 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9204 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9205 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9206 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9207 PetscCall(VecSet(cglobalo, 0.)); 9208 PetscCall(VecSet(clocal, 0.)); 9209 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9210 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9211 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9212 PetscCall(VecSet(fglobal, 0.)); 9213 PetscCall(VecSet(fglobalo, 0.)); 9214 PetscCall(VecSet(flocal, 0.)); 9215 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9216 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9217 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9218 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9219 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9220 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9221 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9222 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9223 *shift = fglobal; 9224 PetscCall(VecDestroy(&flocal)); 9225 PetscCall(VecDestroy(&fglobalo)); 9226 PetscCall(VecDestroy(&clocal)); 9227 PetscCall(VecDestroy(&cglobalo)); 9228 PetscCall(VecDestroy(&rscale)); 9229 PetscCall(MatDestroy(&interpo)); 9230 PetscCall(DMDestroy(&dmfo)); 9231 PetscCall(DMDestroy(&dmco)); 9232 PetscFunctionReturn(0); 9233 } 9234 9235 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9236 { 9237 PetscObject shifto; 9238 Vec shift; 9239 9240 PetscFunctionBegin; 9241 if (!interp) { 9242 Vec rscale; 9243 9244 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9245 PetscCall(VecDestroy(&rscale)); 9246 } else { 9247 PetscCall(PetscObjectReference((PetscObject)interp)); 9248 } 9249 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9250 if (!shifto) { 9251 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9252 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9253 shifto = (PetscObject) shift; 9254 PetscCall(VecDestroy(&shift)); 9255 } 9256 shift = (Vec) shifto; 9257 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9258 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9259 PetscCall(MatDestroy(&interp)); 9260 PetscFunctionReturn(0); 9261 } 9262 9263 /* Pointwise interpolation 9264 Just code FEM for now 9265 u^f = I u^c 9266 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9267 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9268 I_{ij} = psi^f_i phi^c_j 9269 */ 9270 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9271 { 9272 PetscSection gsc, gsf; 9273 PetscInt m, n; 9274 void *ctx; 9275 DM cdm; 9276 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9277 9278 PetscFunctionBegin; 9279 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9280 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9281 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9282 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9283 9284 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9285 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9286 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9287 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9288 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9289 9290 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9291 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9292 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9293 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9294 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9295 if (scaling) { 9296 /* Use naive scaling */ 9297 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9298 } 9299 PetscFunctionReturn(0); 9300 } 9301 9302 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9303 { 9304 VecScatter ctx; 9305 9306 PetscFunctionBegin; 9307 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9308 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9309 PetscCall(VecScatterDestroy(&ctx)); 9310 PetscFunctionReturn(0); 9311 } 9312 9313 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9314 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9315 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9316 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9317 { 9318 const PetscInt Nc = uOff[1] - uOff[0]; 9319 PetscInt c; 9320 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9321 } 9322 9323 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9324 { 9325 DM dmc; 9326 PetscDS ds; 9327 Vec ones, locmass; 9328 IS cellIS; 9329 PetscFormKey key; 9330 PetscInt depth; 9331 9332 PetscFunctionBegin; 9333 PetscCall(DMClone(dm, &dmc)); 9334 PetscCall(DMCopyDisc(dm, dmc)); 9335 PetscCall(DMGetDS(dmc, &ds)); 9336 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9337 PetscCall(DMCreateGlobalVector(dmc, mass)); 9338 PetscCall(DMGetLocalVector(dmc, &ones)); 9339 PetscCall(DMGetLocalVector(dmc, &locmass)); 9340 PetscCall(DMPlexGetDepth(dmc, &depth)); 9341 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9342 PetscCall(VecSet(locmass, 0.0)); 9343 PetscCall(VecSet(ones, 1.0)); 9344 key.label = NULL; 9345 key.value = 0; 9346 key.field = 0; 9347 key.part = 0; 9348 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9349 PetscCall(ISDestroy(&cellIS)); 9350 PetscCall(VecSet(*mass, 0.0)); 9351 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9352 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9353 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9354 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9355 PetscCall(DMDestroy(&dmc)); 9356 PetscFunctionReturn(0); 9357 } 9358 9359 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9360 { 9361 PetscSection gsc, gsf; 9362 PetscInt m, n; 9363 void *ctx; 9364 DM cdm; 9365 PetscBool regular; 9366 9367 PetscFunctionBegin; 9368 if (dmFine == dmCoarse) { 9369 DM dmc; 9370 PetscDS ds; 9371 PetscWeakForm wf; 9372 Vec u; 9373 IS cellIS; 9374 PetscFormKey key; 9375 PetscInt depth; 9376 9377 PetscCall(DMClone(dmFine, &dmc)); 9378 PetscCall(DMCopyDisc(dmFine, dmc)); 9379 PetscCall(DMGetDS(dmc, &ds)); 9380 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9381 PetscCall(PetscWeakFormClear(wf)); 9382 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9383 PetscCall(DMCreateMatrix(dmc, mass)); 9384 PetscCall(DMGetLocalVector(dmc, &u)); 9385 PetscCall(DMPlexGetDepth(dmc, &depth)); 9386 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9387 PetscCall(MatZeroEntries(*mass)); 9388 key.label = NULL; 9389 key.value = 0; 9390 key.field = 0; 9391 key.part = 0; 9392 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9393 PetscCall(ISDestroy(&cellIS)); 9394 PetscCall(DMRestoreLocalVector(dmc, &u)); 9395 PetscCall(DMDestroy(&dmc)); 9396 } else { 9397 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9398 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9399 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9400 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9401 9402 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9403 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9404 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9405 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9406 9407 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9408 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9409 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9410 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9411 } 9412 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9413 PetscFunctionReturn(0); 9414 } 9415 9416 /*@ 9417 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9418 9419 Input Parameter: 9420 . dm - The DMPlex object 9421 9422 Output Parameter: 9423 . regular - The flag 9424 9425 Level: intermediate 9426 9427 .seealso: `DMPlexSetRegularRefinement()` 9428 @*/ 9429 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9430 { 9431 PetscFunctionBegin; 9432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9433 PetscValidBoolPointer(regular, 2); 9434 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9435 PetscFunctionReturn(0); 9436 } 9437 9438 /*@ 9439 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9440 9441 Input Parameters: 9442 + dm - The DMPlex object 9443 - regular - The flag 9444 9445 Level: intermediate 9446 9447 .seealso: `DMPlexGetRegularRefinement()` 9448 @*/ 9449 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9450 { 9451 PetscFunctionBegin; 9452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9453 ((DM_Plex *) dm->data)->regularRefinement = regular; 9454 PetscFunctionReturn(0); 9455 } 9456 9457 /* anchors */ 9458 /*@ 9459 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9460 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9461 9462 not collective 9463 9464 Input Parameter: 9465 . dm - The DMPlex object 9466 9467 Output Parameters: 9468 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9469 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9470 9471 Level: intermediate 9472 9473 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9474 @*/ 9475 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9476 { 9477 DM_Plex *plex = (DM_Plex *)dm->data; 9478 9479 PetscFunctionBegin; 9480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9481 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9482 if (anchorSection) *anchorSection = plex->anchorSection; 9483 if (anchorIS) *anchorIS = plex->anchorIS; 9484 PetscFunctionReturn(0); 9485 } 9486 9487 /*@ 9488 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9489 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9490 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9491 9492 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9493 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9494 9495 collective on dm 9496 9497 Input Parameters: 9498 + dm - The DMPlex object 9499 . 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). 9500 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9501 9502 The reference counts of anchorSection and anchorIS are incremented. 9503 9504 Level: intermediate 9505 9506 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9507 @*/ 9508 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9509 { 9510 DM_Plex *plex = (DM_Plex *)dm->data; 9511 PetscMPIInt result; 9512 9513 PetscFunctionBegin; 9514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9515 if (anchorSection) { 9516 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9517 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9518 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9519 } 9520 if (anchorIS) { 9521 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9522 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9523 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9524 } 9525 9526 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9527 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9528 plex->anchorSection = anchorSection; 9529 9530 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9531 PetscCall(ISDestroy(&plex->anchorIS)); 9532 plex->anchorIS = anchorIS; 9533 9534 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9535 PetscInt size, a, pStart, pEnd; 9536 const PetscInt *anchors; 9537 9538 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9539 PetscCall(ISGetLocalSize(anchorIS,&size)); 9540 PetscCall(ISGetIndices(anchorIS,&anchors)); 9541 for (a = 0; a < size; a++) { 9542 PetscInt p; 9543 9544 p = anchors[a]; 9545 if (p >= pStart && p < pEnd) { 9546 PetscInt dof; 9547 9548 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9549 if (dof) { 9550 9551 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9552 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9553 } 9554 } 9555 } 9556 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9557 } 9558 /* reset the generic constraints */ 9559 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9560 PetscFunctionReturn(0); 9561 } 9562 9563 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9564 { 9565 PetscSection anchorSection; 9566 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9567 9568 PetscFunctionBegin; 9569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9570 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9571 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9572 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9573 if (numFields) { 9574 PetscInt f; 9575 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9576 9577 for (f = 0; f < numFields; f++) { 9578 PetscInt numComp; 9579 9580 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9581 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9582 } 9583 } 9584 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9585 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9586 pStart = PetscMax(pStart,sStart); 9587 pEnd = PetscMin(pEnd,sEnd); 9588 pEnd = PetscMax(pStart,pEnd); 9589 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9590 for (p = pStart; p < pEnd; p++) { 9591 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9592 if (dof) { 9593 PetscCall(PetscSectionGetDof(section,p,&dof)); 9594 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9595 for (f = 0; f < numFields; f++) { 9596 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9597 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9598 } 9599 } 9600 } 9601 PetscCall(PetscSectionSetUp(*cSec)); 9602 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9603 PetscFunctionReturn(0); 9604 } 9605 9606 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9607 { 9608 PetscSection aSec; 9609 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9610 const PetscInt *anchors; 9611 PetscInt numFields, f; 9612 IS aIS; 9613 MatType mtype; 9614 PetscBool iscuda,iskokkos; 9615 9616 PetscFunctionBegin; 9617 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9618 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9619 PetscCall(PetscSectionGetStorageSize(section, &n)); 9620 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9621 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9622 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9623 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9624 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9625 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9626 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9627 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9628 else mtype = MATSEQAIJ; 9629 PetscCall(MatSetType(*cMat,mtype)); 9630 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9631 PetscCall(ISGetIndices(aIS,&anchors)); 9632 /* cSec will be a subset of aSec and section */ 9633 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9634 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9635 PetscCall(PetscMalloc1(m+1,&i)); 9636 i[0] = 0; 9637 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9638 for (p = pStart; p < pEnd; p++) { 9639 PetscInt rDof, rOff, r; 9640 9641 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9642 if (!rDof) continue; 9643 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9644 if (numFields) { 9645 for (f = 0; f < numFields; f++) { 9646 annz = 0; 9647 for (r = 0; r < rDof; r++) { 9648 a = anchors[rOff + r]; 9649 if (a < sStart || a >= sEnd) continue; 9650 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9651 annz += aDof; 9652 } 9653 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9654 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9655 for (q = 0; q < dof; q++) { 9656 i[off + q + 1] = i[off + q] + annz; 9657 } 9658 } 9659 } else { 9660 annz = 0; 9661 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9662 for (q = 0; q < dof; q++) { 9663 a = anchors[rOff + q]; 9664 if (a < sStart || a >= sEnd) continue; 9665 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9666 annz += aDof; 9667 } 9668 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9669 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9670 for (q = 0; q < dof; q++) { 9671 i[off + q + 1] = i[off + q] + annz; 9672 } 9673 } 9674 } 9675 nnz = i[m]; 9676 PetscCall(PetscMalloc1(nnz,&j)); 9677 offset = 0; 9678 for (p = pStart; p < pEnd; p++) { 9679 if (numFields) { 9680 for (f = 0; f < numFields; f++) { 9681 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9682 for (q = 0; q < dof; q++) { 9683 PetscInt rDof, rOff, r; 9684 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9685 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9686 for (r = 0; r < rDof; r++) { 9687 PetscInt s; 9688 9689 a = anchors[rOff + r]; 9690 if (a < sStart || a >= sEnd) continue; 9691 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9692 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9693 for (s = 0; s < aDof; s++) { 9694 j[offset++] = aOff + s; 9695 } 9696 } 9697 } 9698 } 9699 } else { 9700 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9701 for (q = 0; q < dof; q++) { 9702 PetscInt rDof, rOff, r; 9703 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9704 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9705 for (r = 0; r < rDof; r++) { 9706 PetscInt s; 9707 9708 a = anchors[rOff + r]; 9709 if (a < sStart || a >= sEnd) continue; 9710 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9711 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9712 for (s = 0; s < aDof; s++) { 9713 j[offset++] = aOff + s; 9714 } 9715 } 9716 } 9717 } 9718 } 9719 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9720 PetscCall(PetscFree(i)); 9721 PetscCall(PetscFree(j)); 9722 PetscCall(ISRestoreIndices(aIS,&anchors)); 9723 PetscFunctionReturn(0); 9724 } 9725 9726 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9727 { 9728 DM_Plex *plex = (DM_Plex *)dm->data; 9729 PetscSection anchorSection, section, cSec; 9730 Mat cMat; 9731 9732 PetscFunctionBegin; 9733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9734 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9735 if (anchorSection) { 9736 PetscInt Nf; 9737 9738 PetscCall(DMGetLocalSection(dm,§ion)); 9739 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9740 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9741 PetscCall(DMGetNumFields(dm,&Nf)); 9742 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9743 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9744 PetscCall(PetscSectionDestroy(&cSec)); 9745 PetscCall(MatDestroy(&cMat)); 9746 } 9747 PetscFunctionReturn(0); 9748 } 9749 9750 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9751 { 9752 IS subis; 9753 PetscSection section, subsection; 9754 9755 PetscFunctionBegin; 9756 PetscCall(DMGetLocalSection(dm, §ion)); 9757 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9758 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9759 /* Create subdomain */ 9760 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9761 /* Create submodel */ 9762 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9763 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9764 PetscCall(DMSetLocalSection(*subdm, subsection)); 9765 PetscCall(PetscSectionDestroy(&subsection)); 9766 PetscCall(DMCopyDisc(dm, *subdm)); 9767 /* Create map from submodel to global model */ 9768 if (is) { 9769 PetscSection sectionGlobal, subsectionGlobal; 9770 IS spIS; 9771 const PetscInt *spmap; 9772 PetscInt *subIndices; 9773 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9774 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9775 9776 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9777 PetscCall(ISGetIndices(spIS, &spmap)); 9778 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9779 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9780 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9781 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9782 for (p = pStart; p < pEnd; ++p) { 9783 PetscInt gdof, pSubSize = 0; 9784 9785 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9786 if (gdof > 0) { 9787 for (f = 0; f < Nf; ++f) { 9788 PetscInt fdof, fcdof; 9789 9790 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9791 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9792 pSubSize += fdof-fcdof; 9793 } 9794 subSize += pSubSize; 9795 if (pSubSize) { 9796 if (bs < 0) { 9797 bs = pSubSize; 9798 } else if (bs != pSubSize) { 9799 /* Layout does not admit a pointwise block size */ 9800 bs = 1; 9801 } 9802 } 9803 } 9804 } 9805 /* Must have same blocksize on all procs (some might have no points) */ 9806 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9807 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9808 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9809 else {bs = bsMinMax[0];} 9810 PetscCall(PetscMalloc1(subSize, &subIndices)); 9811 for (p = pStart; p < pEnd; ++p) { 9812 PetscInt gdof, goff; 9813 9814 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9815 if (gdof > 0) { 9816 const PetscInt point = spmap[p]; 9817 9818 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9819 for (f = 0; f < Nf; ++f) { 9820 PetscInt fdof, fcdof, fc, f2, poff = 0; 9821 9822 /* Can get rid of this loop by storing field information in the global section */ 9823 for (f2 = 0; f2 < f; ++f2) { 9824 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9825 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9826 poff += fdof-fcdof; 9827 } 9828 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9829 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9830 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9831 subIndices[subOff] = goff+poff+fc; 9832 } 9833 } 9834 } 9835 } 9836 PetscCall(ISRestoreIndices(spIS, &spmap)); 9837 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9838 if (bs > 1) { 9839 /* We need to check that the block size does not come from non-contiguous fields */ 9840 PetscInt i, j, set = 1; 9841 for (i = 0; i < subSize; i += bs) { 9842 for (j = 0; j < bs; ++j) { 9843 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9844 } 9845 } 9846 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9847 } 9848 /* Attach nullspace */ 9849 for (f = 0; f < Nf; ++f) { 9850 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9851 if ((*subdm)->nullspaceConstructors[f]) break; 9852 } 9853 if (f < Nf) { 9854 MatNullSpace nullSpace; 9855 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9856 9857 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9858 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9859 } 9860 } 9861 PetscFunctionReturn(0); 9862 } 9863 9864 /*@ 9865 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9866 9867 Input Parameter: 9868 - dm - The DM 9869 9870 Level: developer 9871 9872 Options Database Keys: 9873 . -dm_plex_monitor_throughput - Activate the monitor 9874 9875 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9876 @*/ 9877 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9878 { 9879 #if defined(PETSC_USE_LOG) 9880 PetscStageLog stageLog; 9881 PetscLogEvent event; 9882 PetscLogStage stage; 9883 PetscEventPerfInfo eventInfo; 9884 PetscReal cellRate, flopRate; 9885 PetscInt cStart, cEnd, Nf, N; 9886 const char *name; 9887 #endif 9888 9889 PetscFunctionBegin; 9890 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9891 #if defined(PETSC_USE_LOG) 9892 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9893 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9894 PetscCall(DMGetNumFields(dm, &Nf)); 9895 PetscCall(PetscLogGetStageLog(&stageLog)); 9896 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9897 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9898 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9899 N = (cEnd - cStart)*Nf*eventInfo.count; 9900 flopRate = eventInfo.flops/eventInfo.time; 9901 cellRate = N/eventInfo.time; 9902 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))); 9903 #else 9904 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9905 #endif 9906 PetscFunctionReturn(0); 9907 } 9908