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; 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 if (isvtk || ishdf5 || isdraw || isglvis) { 444 PetscInt i,numFields; 445 PetscObject fe; 446 PetscBool fem = PETSC_FALSE; 447 Vec locv = v; 448 const char *name; 449 PetscInt step; 450 PetscReal time; 451 452 PetscCall(DMGetNumFields(dm, &numFields)); 453 for (i=0; i<numFields; i++) { 454 PetscCall(DMGetField(dm, i, NULL, &fe)); 455 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 456 } 457 if (fem) { 458 PetscObject isZero; 459 460 PetscCall(DMGetLocalVector(dm, &locv)); 461 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 462 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 463 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 464 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 465 PetscCall(VecCopy(v, locv)); 466 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 467 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 468 } 469 if (isvtk) { 470 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 471 } else if (ishdf5) { 472 #if defined(PETSC_HAVE_HDF5) 473 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 474 #else 475 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 476 #endif 477 } else if (isdraw) { 478 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 479 } else if (isglvis) { 480 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 481 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 482 PetscCall(VecView_GLVis(locv, viewer)); 483 } 484 if (fem) { 485 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 486 PetscCall(DMRestoreLocalVector(dm, &locv)); 487 } 488 } else { 489 PetscBool isseq; 490 491 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 492 if (isseq) PetscCall(VecView_Seq(v, viewer)); 493 else PetscCall(VecView_MPI(v, viewer)); 494 } 495 PetscFunctionReturn(0); 496 } 497 498 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 499 { 500 DM dm; 501 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 502 503 PetscFunctionBegin; 504 PetscCall(VecGetDM(v, &dm)); 505 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 507 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 508 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 509 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 510 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 511 if (isvtk || isdraw || isglvis) { 512 Vec locv; 513 PetscObject isZero; 514 const char *name; 515 516 PetscCall(DMGetLocalVector(dm, &locv)); 517 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 518 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 519 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 520 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 521 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 522 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 523 PetscCall(VecView_Plex_Local(locv, viewer)); 524 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 525 PetscCall(DMRestoreLocalVector(dm, &locv)); 526 } else if (ishdf5) { 527 #if defined(PETSC_HAVE_HDF5) 528 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 529 #else 530 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 531 #endif 532 } else if (isexodusii) { 533 #if defined(PETSC_HAVE_EXODUSII) 534 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 535 #else 536 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 537 #endif 538 } else { 539 PetscBool isseq; 540 541 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 542 if (isseq) PetscCall(VecView_Seq(v, viewer)); 543 else PetscCall(VecView_MPI(v, viewer)); 544 } 545 PetscFunctionReturn(0); 546 } 547 548 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 549 { 550 DM dm; 551 MPI_Comm comm; 552 PetscViewerFormat format; 553 Vec v; 554 PetscBool isvtk, ishdf5; 555 556 PetscFunctionBegin; 557 PetscCall(VecGetDM(originalv, &dm)); 558 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 559 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 560 PetscCall(PetscViewerGetFormat(viewer, &format)); 561 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 562 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 563 if (format == PETSC_VIEWER_NATIVE) { 564 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 565 /* this need a better fix */ 566 if (dm->useNatural) { 567 if (dm->sfNatural) { 568 const char *vecname; 569 PetscInt n, nroots; 570 571 PetscCall(VecGetLocalSize(originalv, &n)); 572 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 573 if (n == nroots) { 574 PetscCall(DMGetGlobalVector(dm, &v)); 575 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 576 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 577 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 578 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 579 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 580 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 581 } else v = originalv; 582 } else v = originalv; 583 584 if (ishdf5) { 585 #if defined(PETSC_HAVE_HDF5) 586 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 587 #else 588 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 589 #endif 590 } else if (isvtk) { 591 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 592 } else { 593 PetscBool isseq; 594 595 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 596 if (isseq) PetscCall(VecView_Seq(v, viewer)); 597 else PetscCall(VecView_MPI(v, viewer)); 598 } 599 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 600 PetscFunctionReturn(0); 601 } 602 603 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 604 { 605 DM dm; 606 PetscBool ishdf5; 607 608 PetscFunctionBegin; 609 PetscCall(VecGetDM(v, &dm)); 610 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 611 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 612 if (ishdf5) { 613 DM dmBC; 614 Vec gv; 615 const char *name; 616 617 PetscCall(DMGetOutputDM(dm, &dmBC)); 618 PetscCall(DMGetGlobalVector(dmBC, &gv)); 619 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 620 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 621 PetscCall(VecLoad_Default(gv, viewer)); 622 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 623 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 624 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 625 } else PetscCall(VecLoad_Default(v, viewer)); 626 PetscFunctionReturn(0); 627 } 628 629 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool ishdf5,isexodusii; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 638 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (ishdf5) { 640 #if defined(PETSC_HAVE_HDF5) 641 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 642 #else 643 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 644 #endif 645 } else if (isexodusii) { 646 #if defined(PETSC_HAVE_EXODUSII) 647 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 648 #else 649 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 650 #endif 651 } else PetscCall(VecLoad_Default(v, viewer)); 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 692 { 693 PetscSection coordSection; 694 Vec coordinates; 695 DMLabel depthLabel, celltypeLabel; 696 const char *name[4]; 697 const PetscScalar *a; 698 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 699 700 PetscFunctionBegin; 701 PetscCall(DMGetDimension(dm, &dim)); 702 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 703 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 704 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 705 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 706 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 707 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 708 PetscCall(VecGetArrayRead(coordinates, &a)); 709 name[0] = "vertex"; 710 name[1] = "edge"; 711 name[dim-1] = "face"; 712 name[dim] = "cell"; 713 for (c = cStart; c < cEnd; ++c) { 714 PetscInt *closure = NULL; 715 PetscInt closureSize, cl, ct; 716 717 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 718 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 719 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 720 PetscCall(PetscViewerASCIIPushTab(viewer)); 721 for (cl = 0; cl < closureSize*2; cl += 2) { 722 PetscInt point = closure[cl], depth, dof, off, d, p; 723 724 if ((point < pStart) || (point >= pEnd)) continue; 725 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 726 if (!dof) continue; 727 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 728 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 729 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 730 for (p = 0; p < dof/dim; ++p) { 731 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 732 for (d = 0; d < dim; ++d) { 733 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 734 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 735 } 736 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 739 } 740 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 741 PetscCall(PetscViewerASCIIPopTab(viewer)); 742 } 743 PetscCall(VecRestoreArrayRead(coordinates, &a)); 744 PetscFunctionReturn(0); 745 } 746 747 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 748 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 749 750 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 751 { 752 PetscInt i; 753 754 PetscFunctionBegin; 755 if (dim > 3) { 756 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 757 } else { 758 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 759 760 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 761 switch (cs) { 762 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 763 case CS_POLAR: 764 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 765 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 766 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 767 break; 768 case CS_CYLINDRICAL: 769 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 trcoords[2] = coords[2]; 773 break; 774 case CS_SPHERICAL: 775 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 776 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 777 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 778 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 779 break; 780 } 781 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 782 } 783 PetscFunctionReturn(0); 784 } 785 786 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 787 { 788 DM_Plex *mesh = (DM_Plex*) dm->data; 789 DM cdm, cdmCell; 790 PetscSection coordSection, coordSectionCell; 791 Vec coordinates, coordinatesCell; 792 PetscViewerFormat format; 793 794 PetscFunctionBegin; 795 PetscCall(DMGetCoordinateDM(dm, &cdm)); 796 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 797 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 798 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 799 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 800 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 801 PetscCall(PetscViewerGetFormat(viewer, &format)); 802 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 803 const char *name; 804 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 805 PetscInt pStart, pEnd, p, numLabels, l; 806 PetscMPIInt rank, size; 807 808 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 809 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 810 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 811 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 812 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 813 PetscCall(DMGetDimension(dm, &dim)); 814 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 815 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 816 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 817 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 818 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 819 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 820 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 821 for (p = pStart; p < pEnd; ++p) { 822 PetscInt dof, off, s; 823 824 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 825 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 826 for (s = off; s < off+dof; ++s) { 827 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 828 } 829 } 830 PetscCall(PetscViewerFlush(viewer)); 831 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 832 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 833 for (p = pStart; p < pEnd; ++p) { 834 PetscInt dof, off, c; 835 836 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 837 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 838 for (c = off; c < off+dof; ++c) { 839 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 840 } 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize*2; p += 2) { 992 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 993 } 994 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 995 } 996 } 997 } 998 999 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1000 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1001 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1003 \\documentclass[tikz]{standalone}\n\n\ 1004 \\usepackage{pgflibraryshapes}\n\ 1005 \\usetikzlibrary{backgrounds}\n\ 1006 \\usetikzlibrary{arrows}\n\ 1007 \\begin{document}\n")); 1008 if (size > 1) { 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1010 for (p = 0; p < size; ++p) { 1011 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1012 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1013 } 1014 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1015 } 1016 if (drawHasse) { 1017 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1018 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1031 } 1032 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1033 1034 /* Plot vertices */ 1035 PetscCall(VecGetArray(coordinates, &coords)); 1036 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1037 for (v = vStart; v < vEnd; ++v) { 1038 PetscInt off, dof, d; 1039 PetscBool isLabeled = PETSC_FALSE; 1040 1041 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1042 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1043 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1044 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1045 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1046 for (d = 0; d < dof; ++d) { 1047 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1048 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1049 } 1050 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1051 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1052 for (d = 0; d < dof; ++d) { 1053 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1054 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1055 } 1056 if (drawHasse) color = colors[0%numColors]; 1057 else color = colors[rank%numColors]; 1058 for (l = 0; l < numLabels; ++l) { 1059 PetscInt val; 1060 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1061 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1062 } 1063 if (drawNumbers[0]) { 1064 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1065 } else if (drawColors[0]) { 1066 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1067 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1068 } 1069 PetscCall(VecRestoreArray(coordinates, &coords)); 1070 PetscCall(PetscViewerFlush(viewer)); 1071 /* Plot edges */ 1072 if (plotEdges) { 1073 PetscCall(VecGetArray(coordinates, &coords)); 1074 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1075 for (e = eStart; e < eEnd; ++e) { 1076 const PetscInt *cone; 1077 PetscInt coneSize, offA, offB, dof, d; 1078 1079 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1080 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1081 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1082 PetscCall(DMPlexGetCone(dm, e, &cone)); 1083 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1084 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1085 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1086 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1087 for (d = 0; d < dof; ++d) { 1088 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1089 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1090 } 1091 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1092 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1093 for (d = 0; d < dof; ++d) { 1094 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1095 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1096 } 1097 if (drawHasse) color = colors[1%numColors]; 1098 else color = colors[rank%numColors]; 1099 for (l = 0; l < numLabels; ++l) { 1100 PetscInt val; 1101 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1102 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1103 } 1104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1105 } 1106 PetscCall(VecRestoreArray(coordinates, &coords)); 1107 PetscCall(PetscViewerFlush(viewer)); 1108 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1109 } 1110 /* Plot cells */ 1111 if (dim == 3 || !drawNumbers[1]) { 1112 for (e = eStart; e < eEnd; ++e) { 1113 const PetscInt *cone; 1114 1115 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1116 color = colors[rank%numColors]; 1117 for (l = 0; l < numLabels; ++l) { 1118 PetscInt val; 1119 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1120 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1121 } 1122 PetscCall(DMPlexGetCone(dm, e, &cone)); 1123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1124 } 1125 } else { 1126 DMPolytopeType ct; 1127 1128 /* Drawing a 2D polygon */ 1129 for (c = cStart; c < cEnd; ++c) { 1130 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1131 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1132 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1133 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1134 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1135 const PetscInt *cone; 1136 PetscInt coneSize, e; 1137 1138 PetscCall(DMPlexGetCone(dm, c, &cone)); 1139 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1140 for (e = 0; e < coneSize; ++e) { 1141 const PetscInt *econe; 1142 1143 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1144 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)); 1145 } 1146 } else { 1147 PetscInt *closure = NULL; 1148 PetscInt closureSize, Nv = 0, v; 1149 1150 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1151 for (p = 0; p < closureSize*2; p += 2) { 1152 const PetscInt point = closure[p]; 1153 1154 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1155 } 1156 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1157 for (v = 0; v <= Nv; ++v) { 1158 const PetscInt vertex = closure[v%Nv]; 1159 1160 if (v > 0) { 1161 if (plotEdges) { 1162 const PetscInt *edge; 1163 PetscInt endpoints[2], ne; 1164 1165 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1166 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1167 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1168 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1169 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1170 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1171 } 1172 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1173 } 1174 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1175 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1176 } 1177 } 1178 } 1179 PetscCall(VecGetArray(coordinates, &coords)); 1180 for (c = cStart; c < cEnd; ++c) { 1181 double ccoords[3] = {0.0, 0.0, 0.0}; 1182 PetscBool isLabeled = PETSC_FALSE; 1183 PetscInt *closure = NULL; 1184 PetscInt closureSize, dof, d, n = 0; 1185 1186 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1187 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1188 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1189 for (p = 0; p < closureSize*2; p += 2) { 1190 const PetscInt point = closure[p]; 1191 PetscInt off; 1192 1193 if ((point < vStart) || (point >= vEnd)) continue; 1194 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1195 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1196 for (d = 0; d < dof; ++d) { 1197 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1198 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1199 } 1200 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1201 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1202 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1203 ++n; 1204 } 1205 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1206 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1207 for (d = 0; d < dof; ++d) { 1208 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1210 } 1211 if (drawHasse) color = colors[depth%numColors]; 1212 else color = colors[rank%numColors]; 1213 for (l = 0; l < numLabels; ++l) { 1214 PetscInt val; 1215 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1216 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1217 } 1218 if (drawNumbers[dim]) { 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1220 } else if (drawColors[dim]) { 1221 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1222 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1223 } 1224 PetscCall(VecRestoreArray(coordinates, &coords)); 1225 if (drawHasse) { 1226 color = colors[depth%numColors]; 1227 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1232 1233 color = colors[1%numColors]; 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1235 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1237 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1239 1240 color = colors[0%numColors]; 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1242 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1244 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1246 1247 for (p = pStart; p < pEnd; ++p) { 1248 const PetscInt *cone; 1249 PetscInt coneSize, cp; 1250 1251 PetscCall(DMPlexGetCone(dm, p, &cone)); 1252 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1253 for (cp = 0; cp < coneSize; ++cp) { 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1255 } 1256 } 1257 } 1258 PetscCall(PetscViewerFlush(viewer)); 1259 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1262 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1263 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1264 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1265 PetscCall(PetscFree3(names, colors, lcolors)); 1266 PetscCall(PetscBTDestroy(&wp)); 1267 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1268 Vec cown,acown; 1269 VecScatter sct; 1270 ISLocalToGlobalMapping g2l; 1271 IS gid,acis; 1272 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1273 MPI_Group ggroup,ngroup; 1274 PetscScalar *array,nid; 1275 const PetscInt *idxs; 1276 PetscInt *idxs2,*start,*adjacency,*work; 1277 PetscInt64 lm[3],gm[3]; 1278 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1279 PetscMPIInt d1,d2,rank; 1280 1281 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1282 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1283 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1284 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1285 #endif 1286 if (ncomm != MPI_COMM_NULL) { 1287 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1288 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1289 d1 = 0; 1290 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1291 nid = d2; 1292 PetscCallMPI(MPI_Group_free(&ggroup)); 1293 PetscCallMPI(MPI_Group_free(&ngroup)); 1294 PetscCallMPI(MPI_Comm_free(&ncomm)); 1295 } else nid = 0.0; 1296 1297 /* Get connectivity */ 1298 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1299 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1300 1301 /* filter overlapped local cells */ 1302 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1303 PetscCall(ISGetIndices(gid,&idxs)); 1304 PetscCall(ISGetLocalSize(gid,&cum)); 1305 PetscCall(PetscMalloc1(cum,&idxs2)); 1306 for (c = cStart, cum = 0; c < cEnd; c++) { 1307 if (idxs[c-cStart] < 0) continue; 1308 idxs2[cum++] = idxs[c-cStart]; 1309 } 1310 PetscCall(ISRestoreIndices(gid,&idxs)); 1311 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1312 PetscCall(ISDestroy(&gid)); 1313 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1314 1315 /* support for node-aware cell locality */ 1316 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1317 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1318 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1319 PetscCall(VecGetArray(cown,&array)); 1320 for (c = 0; c < numVertices; c++) array[c] = nid; 1321 PetscCall(VecRestoreArray(cown,&array)); 1322 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1323 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1324 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1325 PetscCall(ISDestroy(&acis)); 1326 PetscCall(VecScatterDestroy(&sct)); 1327 PetscCall(VecDestroy(&cown)); 1328 1329 /* compute edgeCut */ 1330 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1331 PetscCall(PetscMalloc1(cum,&work)); 1332 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1333 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1334 PetscCall(ISDestroy(&gid)); 1335 PetscCall(VecGetArray(acown,&array)); 1336 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1337 PetscInt totl; 1338 1339 totl = start[c+1]-start[c]; 1340 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1341 for (i = 0; i < totl; i++) { 1342 if (work[i] < 0) { 1343 ect += 1; 1344 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1345 } 1346 } 1347 } 1348 PetscCall(PetscFree(work)); 1349 PetscCall(VecRestoreArray(acown,&array)); 1350 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1351 lm[1] = -numVertices; 1352 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1353 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1354 lm[0] = ect; /* edgeCut */ 1355 lm[1] = ectn; /* node-aware edgeCut */ 1356 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1357 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1358 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1359 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1360 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1361 #else 1362 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1363 #endif 1364 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1365 PetscCall(PetscFree(start)); 1366 PetscCall(PetscFree(adjacency)); 1367 PetscCall(VecDestroy(&acown)); 1368 } else { 1369 const char *name; 1370 PetscInt *sizes, *hybsizes, *ghostsizes; 1371 PetscInt locDepth, depth, cellHeight, dim, d; 1372 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1373 PetscInt numLabels, l, maxSize = 17; 1374 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1375 MPI_Comm comm; 1376 PetscMPIInt size, rank; 1377 1378 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1379 PetscCallMPI(MPI_Comm_size(comm, &size)); 1380 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1381 PetscCall(DMGetDimension(dm, &dim)); 1382 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1383 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1384 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1385 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1386 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1387 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1388 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1389 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1390 gcNum = gcEnd - gcStart; 1391 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1392 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1393 for (d = 0; d <= depth; d++) { 1394 PetscInt Nc[2] = {0, 0}, ict; 1395 1396 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1397 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1398 ict = ct0; 1399 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1400 ct0 = (DMPolytopeType) ict; 1401 for (p = pStart; p < pEnd; ++p) { 1402 DMPolytopeType ct; 1403 1404 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1405 if (ct == ct0) ++Nc[0]; 1406 else ++Nc[1]; 1407 } 1408 if (size < maxSize) { 1409 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1410 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1411 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1412 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1413 for (p = 0; p < size; ++p) { 1414 if (rank == 0) { 1415 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1416 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1417 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1418 } 1419 } 1420 } else { 1421 PetscInt locMinMax[2]; 1422 1423 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1424 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1425 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1426 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1427 if (d == depth) { 1428 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1429 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1430 } 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1433 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1434 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1435 } 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1437 } 1438 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1439 { 1440 const PetscReal *maxCell; 1441 const PetscReal *L; 1442 PetscBool localized; 1443 1444 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1445 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1446 if (L || localized) { 1447 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1448 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1449 if (L) { 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1451 for (d = 0; d < dim; ++d) { 1452 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1453 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1456 } 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1458 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1459 } 1460 } 1461 PetscCall(DMGetNumLabels(dm, &numLabels)); 1462 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1463 for (l = 0; l < numLabels; ++l) { 1464 DMLabel label; 1465 const char *name; 1466 IS valueIS; 1467 const PetscInt *values; 1468 PetscInt numValues, v; 1469 1470 PetscCall(DMGetLabelName(dm, l, &name)); 1471 PetscCall(DMGetLabel(dm, name, &label)); 1472 PetscCall(DMLabelGetNumValues(label, &numValues)); 1473 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1474 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1475 PetscCall(ISGetIndices(valueIS, &values)); 1476 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1477 for (v = 0; v < numValues; ++v) { 1478 PetscInt size; 1479 1480 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1481 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1483 } 1484 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1485 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1486 PetscCall(ISRestoreIndices(valueIS, &values)); 1487 PetscCall(ISDestroy(&valueIS)); 1488 } 1489 { 1490 char **labelNames; 1491 PetscInt Nl = numLabels; 1492 PetscBool flg; 1493 1494 PetscCall(PetscMalloc1(Nl, &labelNames)); 1495 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1496 for (l = 0; l < Nl; ++l) { 1497 DMLabel label; 1498 1499 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1500 if (flg) { 1501 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1502 PetscCall(DMLabelView(label, viewer)); 1503 } 1504 PetscCall(PetscFree(labelNames[l])); 1505 } 1506 PetscCall(PetscFree(labelNames)); 1507 } 1508 /* If no fields are specified, people do not want to see adjacency */ 1509 if (dm->Nf) { 1510 PetscInt f; 1511 1512 for (f = 0; f < dm->Nf; ++f) { 1513 const char *name; 1514 1515 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1516 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1517 PetscCall(PetscViewerASCIIPushTab(viewer)); 1518 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1519 if (dm->fields[f].adjacency[0]) { 1520 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1521 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1522 } else { 1523 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1524 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1525 } 1526 PetscCall(PetscViewerASCIIPopTab(viewer)); 1527 } 1528 } 1529 PetscCall(DMGetCoarseDM(dm, &cdm)); 1530 if (cdm) { 1531 PetscCall(PetscViewerASCIIPushTab(viewer)); 1532 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1533 PetscCall(PetscViewerASCIIPopTab(viewer)); 1534 } 1535 } 1536 PetscFunctionReturn(0); 1537 } 1538 1539 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1540 { 1541 DMPolytopeType ct; 1542 PetscMPIInt rank; 1543 PetscInt cdim; 1544 1545 PetscFunctionBegin; 1546 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1547 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1548 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1549 switch (ct) { 1550 case DM_POLYTOPE_SEGMENT: 1551 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1552 switch (cdim) { 1553 case 1: 1554 { 1555 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1556 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1557 1558 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1559 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1560 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1561 } 1562 break; 1563 case 2: 1564 { 1565 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1566 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1567 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1568 1569 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1570 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)); 1571 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)); 1572 } 1573 break; 1574 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1575 } 1576 break; 1577 case DM_POLYTOPE_TRIANGLE: 1578 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1579 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1580 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1581 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1583 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1585 break; 1586 case DM_POLYTOPE_QUADRILATERAL: 1587 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1588 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1589 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1590 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1591 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1592 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1593 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1594 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1596 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1597 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1598 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1599 break; 1600 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1601 } 1602 PetscFunctionReturn(0); 1603 } 1604 1605 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1606 { 1607 DMPolytopeType ct; 1608 PetscReal centroid[2] = {0., 0.}; 1609 PetscMPIInt rank; 1610 PetscInt fillColor, v, e, d; 1611 1612 PetscFunctionBegin; 1613 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1614 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1615 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1616 switch (ct) { 1617 case DM_POLYTOPE_TRIANGLE: 1618 { 1619 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1620 1621 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1622 for (e = 0; e < 3; ++e) { 1623 refCoords[0] = refVertices[e*2+0]; 1624 refCoords[1] = refVertices[e*2+1]; 1625 for (d = 1; d <= edgeDiv; ++d) { 1626 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1627 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1628 } 1629 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1630 for (d = 0; d < edgeDiv; ++d) { 1631 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)); 1632 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1633 } 1634 } 1635 } 1636 break; 1637 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1638 } 1639 PetscFunctionReturn(0); 1640 } 1641 1642 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1643 { 1644 PetscDraw draw; 1645 DM cdm; 1646 PetscSection coordSection; 1647 Vec coordinates; 1648 const PetscScalar *coords; 1649 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1650 PetscReal *refCoords, *edgeCoords; 1651 PetscBool isnull, drawAffine = PETSC_TRUE; 1652 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1653 1654 PetscFunctionBegin; 1655 PetscCall(DMGetCoordinateDim(dm, &dim)); 1656 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1657 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1658 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1659 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1660 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1661 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1662 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1663 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1664 1665 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1666 PetscCall(PetscDrawIsNull(draw, &isnull)); 1667 if (isnull) PetscFunctionReturn(0); 1668 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1669 1670 PetscCall(VecGetLocalSize(coordinates, &N)); 1671 PetscCall(VecGetArrayRead(coordinates, &coords)); 1672 for (c = 0; c < N; c += dim) { 1673 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1674 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1675 } 1676 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1677 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1678 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1679 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1680 PetscCall(PetscDrawClear(draw)); 1681 1682 for (c = cStart; c < cEnd; ++c) { 1683 PetscScalar *coords = NULL; 1684 PetscInt numCoords; 1685 1686 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1687 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1688 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1689 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1690 } 1691 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1692 PetscCall(PetscDrawFlush(draw)); 1693 PetscCall(PetscDrawPause(draw)); 1694 PetscCall(PetscDrawSave(draw)); 1695 PetscFunctionReturn(0); 1696 } 1697 1698 #if defined(PETSC_HAVE_EXODUSII) 1699 #include <exodusII.h> 1700 #include <petscviewerexodusii.h> 1701 #endif 1702 1703 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1704 { 1705 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1706 char name[PETSC_MAX_PATH_LEN]; 1707 1708 PetscFunctionBegin; 1709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1710 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1711 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1712 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1713 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1714 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1715 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1716 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1717 if (iascii) { 1718 PetscViewerFormat format; 1719 PetscCall(PetscViewerGetFormat(viewer, &format)); 1720 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1721 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1722 } else if (ishdf5) { 1723 #if defined(PETSC_HAVE_HDF5) 1724 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1725 #else 1726 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1727 #endif 1728 } else if (isvtk) { 1729 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1730 } else if (isdraw) { 1731 PetscCall(DMPlexView_Draw(dm, viewer)); 1732 } else if (isglvis) { 1733 PetscCall(DMPlexView_GLVis(dm, viewer)); 1734 #if defined(PETSC_HAVE_EXODUSII) 1735 } else if (isexodus) { 1736 /* 1737 exodusII requires that all sets be part of exactly one cell set. 1738 If the dm does not have a "Cell Sets" label defined, we create one 1739 with ID 1, containig all cells. 1740 Note that if the Cell Sets label is defined but does not cover all cells, 1741 we may still have a problem. This should probably be checked here or in the viewer; 1742 */ 1743 PetscInt numCS; 1744 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1745 if (!numCS) { 1746 PetscInt cStart, cEnd, c; 1747 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1748 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1749 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1750 } 1751 PetscCall(DMView_PlexExodusII(dm, viewer)); 1752 #endif 1753 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1754 1755 /* Optionally view the partition */ 1756 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1757 if (flg) { 1758 Vec ranks; 1759 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1760 PetscCall(VecView(ranks, viewer)); 1761 PetscCall(VecDestroy(&ranks)); 1762 } 1763 /* Optionally view a label */ 1764 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1765 if (flg) { 1766 DMLabel label; 1767 Vec val; 1768 1769 PetscCall(DMGetLabel(dm, name, &label)); 1770 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1771 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1772 PetscCall(VecView(val, viewer)); 1773 PetscCall(VecDestroy(&val)); 1774 } 1775 PetscFunctionReturn(0); 1776 } 1777 1778 /*@ 1779 DMPlexTopologyView - Saves a DMPlex topology into a file 1780 1781 Collective on DM 1782 1783 Input Parameters: 1784 + dm - The DM whose topology is to be saved 1785 - viewer - The PetscViewer for saving 1786 1787 Level: advanced 1788 1789 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1790 @*/ 1791 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1792 { 1793 PetscBool ishdf5; 1794 1795 PetscFunctionBegin; 1796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1797 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1798 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1799 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1800 if (ishdf5) { 1801 #if defined(PETSC_HAVE_HDF5) 1802 PetscViewerFormat format; 1803 PetscCall(PetscViewerGetFormat(viewer, &format)); 1804 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1805 IS globalPointNumbering; 1806 1807 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1808 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1809 PetscCall(ISDestroy(&globalPointNumbering)); 1810 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1811 #else 1812 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1813 #endif 1814 } 1815 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1816 PetscFunctionReturn(0); 1817 } 1818 1819 /*@ 1820 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1821 1822 Collective on DM 1823 1824 Input Parameters: 1825 + dm - The DM whose coordinates are to be saved 1826 - viewer - The PetscViewer for saving 1827 1828 Level: advanced 1829 1830 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1831 @*/ 1832 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1833 { 1834 PetscBool ishdf5; 1835 1836 PetscFunctionBegin; 1837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1838 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1839 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1840 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1841 if (ishdf5) { 1842 #if defined(PETSC_HAVE_HDF5) 1843 PetscViewerFormat format; 1844 PetscCall(PetscViewerGetFormat(viewer, &format)); 1845 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1846 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1847 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1848 #else 1849 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1850 #endif 1851 } 1852 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1853 PetscFunctionReturn(0); 1854 } 1855 1856 /*@ 1857 DMPlexLabelsView - Saves DMPlex labels into a file 1858 1859 Collective on DM 1860 1861 Input Parameters: 1862 + dm - The DM whose labels are to be saved 1863 - viewer - The PetscViewer for saving 1864 1865 Level: advanced 1866 1867 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1868 @*/ 1869 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1870 { 1871 PetscBool ishdf5; 1872 1873 PetscFunctionBegin; 1874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1875 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1876 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1877 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1878 if (ishdf5) { 1879 #if defined(PETSC_HAVE_HDF5) 1880 IS globalPointNumbering; 1881 PetscViewerFormat format; 1882 1883 PetscCall(PetscViewerGetFormat(viewer, &format)); 1884 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1885 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1886 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1887 PetscCall(ISDestroy(&globalPointNumbering)); 1888 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1889 #else 1890 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1891 #endif 1892 } 1893 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1894 PetscFunctionReturn(0); 1895 } 1896 1897 /*@ 1898 DMPlexSectionView - Saves a section associated with a DMPlex 1899 1900 Collective on DM 1901 1902 Input Parameters: 1903 + dm - The DM that contains the topology on which the section to be saved is defined 1904 . viewer - The PetscViewer for saving 1905 - sectiondm - The DM that contains the section to be saved 1906 1907 Level: advanced 1908 1909 Notes: 1910 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. 1911 1912 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. 1913 1914 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1915 @*/ 1916 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1917 { 1918 PetscBool ishdf5; 1919 1920 PetscFunctionBegin; 1921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1922 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1923 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1924 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1925 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1926 if (ishdf5) { 1927 #if defined(PETSC_HAVE_HDF5) 1928 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1929 #else 1930 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1931 #endif 1932 } 1933 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1934 PetscFunctionReturn(0); 1935 } 1936 1937 /*@ 1938 DMPlexGlobalVectorView - Saves a global vector 1939 1940 Collective on DM 1941 1942 Input Parameters: 1943 + dm - The DM that represents the topology 1944 . viewer - The PetscViewer to save data with 1945 . sectiondm - The DM that contains the global section on which vec is defined 1946 - vec - The global vector to be saved 1947 1948 Level: advanced 1949 1950 Notes: 1951 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. 1952 1953 Typical calling sequence 1954 $ DMCreate(PETSC_COMM_WORLD, &dm); 1955 $ DMSetType(dm, DMPLEX); 1956 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1957 $ DMClone(dm, §iondm); 1958 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1959 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1960 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1961 $ PetscSectionSetChart(section, pStart, pEnd); 1962 $ PetscSectionSetUp(section); 1963 $ DMSetLocalSection(sectiondm, section); 1964 $ PetscSectionDestroy(§ion); 1965 $ DMGetGlobalVector(sectiondm, &vec); 1966 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1967 $ DMPlexTopologyView(dm, viewer); 1968 $ DMPlexSectionView(dm, viewer, sectiondm); 1969 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1970 $ DMRestoreGlobalVector(sectiondm, &vec); 1971 $ DMDestroy(§iondm); 1972 $ DMDestroy(&dm); 1973 1974 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1975 @*/ 1976 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1977 { 1978 PetscBool ishdf5; 1979 1980 PetscFunctionBegin; 1981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1982 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1983 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1984 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1985 /* Check consistency */ 1986 { 1987 PetscSection section; 1988 PetscBool includesConstraints; 1989 PetscInt m, m1; 1990 1991 PetscCall(VecGetLocalSize(vec, &m1)); 1992 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1993 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1994 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1995 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1996 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1997 } 1998 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1999 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2000 if (ishdf5) { 2001 #if defined(PETSC_HAVE_HDF5) 2002 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2003 #else 2004 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2005 #endif 2006 } 2007 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2008 PetscFunctionReturn(0); 2009 } 2010 2011 /*@ 2012 DMPlexLocalVectorView - Saves a local vector 2013 2014 Collective on DM 2015 2016 Input Parameters: 2017 + dm - The DM that represents the topology 2018 . viewer - The PetscViewer to save data with 2019 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2020 - vec - The local vector to be saved 2021 2022 Level: advanced 2023 2024 Notes: 2025 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. 2026 2027 Typical calling sequence 2028 $ DMCreate(PETSC_COMM_WORLD, &dm); 2029 $ DMSetType(dm, DMPLEX); 2030 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2031 $ DMClone(dm, §iondm); 2032 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2033 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2034 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2035 $ PetscSectionSetChart(section, pStart, pEnd); 2036 $ PetscSectionSetUp(section); 2037 $ DMSetLocalSection(sectiondm, section); 2038 $ DMGetLocalVector(sectiondm, &vec); 2039 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2040 $ DMPlexTopologyView(dm, viewer); 2041 $ DMPlexSectionView(dm, viewer, sectiondm); 2042 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2043 $ DMRestoreLocalVector(sectiondm, &vec); 2044 $ DMDestroy(§iondm); 2045 $ DMDestroy(&dm); 2046 2047 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2048 @*/ 2049 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2050 { 2051 PetscBool ishdf5; 2052 2053 PetscFunctionBegin; 2054 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2055 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2056 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2057 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2058 /* Check consistency */ 2059 { 2060 PetscSection section; 2061 PetscBool includesConstraints; 2062 PetscInt m, m1; 2063 2064 PetscCall(VecGetLocalSize(vec, &m1)); 2065 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2066 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2067 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2068 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2069 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2070 } 2071 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2072 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2073 if (ishdf5) { 2074 #if defined(PETSC_HAVE_HDF5) 2075 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2076 #else 2077 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2078 #endif 2079 } 2080 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2081 PetscFunctionReturn(0); 2082 } 2083 2084 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2085 { 2086 PetscBool ishdf5; 2087 2088 PetscFunctionBegin; 2089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2090 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2091 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2092 if (ishdf5) { 2093 #if defined(PETSC_HAVE_HDF5) 2094 PetscViewerFormat format; 2095 PetscCall(PetscViewerGetFormat(viewer, &format)); 2096 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2097 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2098 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2099 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2100 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2101 PetscFunctionReturn(0); 2102 #else 2103 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2104 #endif 2105 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2106 } 2107 2108 /*@ 2109 DMPlexTopologyLoad - Loads a topology into a DMPlex 2110 2111 Collective on DM 2112 2113 Input Parameters: 2114 + dm - The DM into which the topology is loaded 2115 - viewer - The PetscViewer for the saved topology 2116 2117 Output Parameters: 2118 . 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 2119 2120 Level: advanced 2121 2122 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2123 @*/ 2124 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2125 { 2126 PetscBool ishdf5; 2127 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2130 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2131 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2132 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2133 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2134 if (ishdf5) { 2135 #if defined(PETSC_HAVE_HDF5) 2136 PetscViewerFormat format; 2137 PetscCall(PetscViewerGetFormat(viewer, &format)); 2138 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2139 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2140 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2141 #else 2142 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2143 #endif 2144 } 2145 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2146 PetscFunctionReturn(0); 2147 } 2148 2149 /*@ 2150 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2151 2152 Collective on DM 2153 2154 Input Parameters: 2155 + dm - The DM into which the coordinates are loaded 2156 . viewer - The PetscViewer for the saved coordinates 2157 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2158 2159 Level: advanced 2160 2161 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2162 @*/ 2163 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2164 { 2165 PetscBool ishdf5; 2166 2167 PetscFunctionBegin; 2168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2169 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2170 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2171 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2172 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2173 if (ishdf5) { 2174 #if defined(PETSC_HAVE_HDF5) 2175 PetscViewerFormat format; 2176 PetscCall(PetscViewerGetFormat(viewer, &format)); 2177 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2178 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2179 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2180 #else 2181 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2182 #endif 2183 } 2184 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2185 PetscFunctionReturn(0); 2186 } 2187 2188 /*@ 2189 DMPlexLabelsLoad - Loads labels into a DMPlex 2190 2191 Collective on DM 2192 2193 Input Parameters: 2194 + dm - The DM into which the labels are loaded 2195 . viewer - The PetscViewer for the saved labels 2196 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2197 2198 Level: advanced 2199 2200 Notes: 2201 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2202 2203 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2204 @*/ 2205 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2206 { 2207 PetscBool ishdf5; 2208 2209 PetscFunctionBegin; 2210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2211 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2212 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2213 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2214 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2215 if (ishdf5) { 2216 #if defined(PETSC_HAVE_HDF5) 2217 PetscViewerFormat format; 2218 2219 PetscCall(PetscViewerGetFormat(viewer, &format)); 2220 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2221 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2222 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2223 #else 2224 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2225 #endif 2226 } 2227 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2228 PetscFunctionReturn(0); 2229 } 2230 2231 /*@ 2232 DMPlexSectionLoad - Loads section into a DMPlex 2233 2234 Collective on DM 2235 2236 Input Parameters: 2237 + dm - The DM that represents the topology 2238 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2239 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2240 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2241 2242 Output Parameters 2243 + 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) 2244 - 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) 2245 2246 Level: advanced 2247 2248 Notes: 2249 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. 2250 2251 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. 2252 2253 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. 2254 2255 Example using 2 processes: 2256 $ NX (number of points on dm): 4 2257 $ sectionA : the on-disk section 2258 $ vecA : a vector associated with sectionA 2259 $ sectionB : sectiondm's local section constructed in this function 2260 $ vecB (local) : a vector associated with sectiondm's local section 2261 $ vecB (global) : a vector associated with sectiondm's global section 2262 $ 2263 $ rank 0 rank 1 2264 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2265 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2267 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2268 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2269 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2270 $ sectionB->atlasDof : 1 0 1 | 1 3 2271 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2272 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2273 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2274 $ 2275 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2276 2277 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2278 @*/ 2279 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2280 { 2281 PetscBool ishdf5; 2282 2283 PetscFunctionBegin; 2284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2285 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2286 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2287 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2288 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2289 if (localDofSF) PetscValidPointer(localDofSF, 6); 2290 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2291 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2292 if (ishdf5) { 2293 #if defined(PETSC_HAVE_HDF5) 2294 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2295 #else 2296 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2297 #endif 2298 } 2299 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2300 PetscFunctionReturn(0); 2301 } 2302 2303 /*@ 2304 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2305 2306 Collective on DM 2307 2308 Input Parameters: 2309 + dm - The DM that represents the topology 2310 . viewer - The PetscViewer that represents the on-disk vector data 2311 . sectiondm - The DM that contains the global section on which vec is defined 2312 . sf - The SF that migrates the on-disk vector data into vec 2313 - vec - The global vector to set values of 2314 2315 Level: advanced 2316 2317 Notes: 2318 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. 2319 2320 Typical calling sequence 2321 $ DMCreate(PETSC_COMM_WORLD, &dm); 2322 $ DMSetType(dm, DMPLEX); 2323 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2324 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2325 $ DMClone(dm, §iondm); 2326 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2327 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2328 $ DMGetGlobalVector(sectiondm, &vec); 2329 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2330 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2331 $ DMRestoreGlobalVector(sectiondm, &vec); 2332 $ PetscSFDestroy(&gsf); 2333 $ PetscSFDestroy(&sfX); 2334 $ DMDestroy(§iondm); 2335 $ DMDestroy(&dm); 2336 2337 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2338 @*/ 2339 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2340 { 2341 PetscBool ishdf5; 2342 2343 PetscFunctionBegin; 2344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2345 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2346 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2347 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2348 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2349 /* Check consistency */ 2350 { 2351 PetscSection section; 2352 PetscBool includesConstraints; 2353 PetscInt m, m1; 2354 2355 PetscCall(VecGetLocalSize(vec, &m1)); 2356 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2357 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2358 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2359 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2360 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2361 } 2362 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2363 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2364 if (ishdf5) { 2365 #if defined(PETSC_HAVE_HDF5) 2366 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2367 #else 2368 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2369 #endif 2370 } 2371 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2372 PetscFunctionReturn(0); 2373 } 2374 2375 /*@ 2376 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2377 2378 Collective on DM 2379 2380 Input Parameters: 2381 + dm - The DM that represents the topology 2382 . viewer - The PetscViewer that represents the on-disk vector data 2383 . sectiondm - The DM that contains the local section on which vec is defined 2384 . sf - The SF that migrates the on-disk vector data into vec 2385 - vec - The local vector to set values of 2386 2387 Level: advanced 2388 2389 Notes: 2390 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. 2391 2392 Typical calling sequence 2393 $ DMCreate(PETSC_COMM_WORLD, &dm); 2394 $ DMSetType(dm, DMPLEX); 2395 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2396 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2397 $ DMClone(dm, §iondm); 2398 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2399 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2400 $ DMGetLocalVector(sectiondm, &vec); 2401 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2402 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2403 $ DMRestoreLocalVector(sectiondm, &vec); 2404 $ PetscSFDestroy(&lsf); 2405 $ PetscSFDestroy(&sfX); 2406 $ DMDestroy(§iondm); 2407 $ DMDestroy(&dm); 2408 2409 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2410 @*/ 2411 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2412 { 2413 PetscBool ishdf5; 2414 2415 PetscFunctionBegin; 2416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2417 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2418 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2419 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2420 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2421 /* Check consistency */ 2422 { 2423 PetscSection section; 2424 PetscBool includesConstraints; 2425 PetscInt m, m1; 2426 2427 PetscCall(VecGetLocalSize(vec, &m1)); 2428 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2429 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2430 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2431 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2432 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2433 } 2434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2435 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2436 if (ishdf5) { 2437 #if defined(PETSC_HAVE_HDF5) 2438 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2439 #else 2440 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2441 #endif 2442 } 2443 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2444 PetscFunctionReturn(0); 2445 } 2446 2447 PetscErrorCode DMDestroy_Plex(DM dm) 2448 { 2449 DM_Plex *mesh = (DM_Plex*) dm->data; 2450 2451 PetscFunctionBegin; 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2461 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2462 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2463 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2464 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2465 if (--mesh->refct > 0) PetscFunctionReturn(0); 2466 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2467 PetscCall(PetscFree(mesh->cones)); 2468 PetscCall(PetscFree(mesh->coneOrientations)); 2469 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2470 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2471 PetscCall(PetscFree(mesh->supports)); 2472 PetscCall(PetscFree(mesh->facesTmp)); 2473 PetscCall(PetscFree(mesh->tetgenOpts)); 2474 PetscCall(PetscFree(mesh->triangleOpts)); 2475 PetscCall(PetscFree(mesh->transformType)); 2476 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2477 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2478 PetscCall(ISDestroy(&mesh->subpointIS)); 2479 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2480 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2481 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2482 PetscCall(ISDestroy(&mesh->anchorIS)); 2483 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2484 PetscCall(PetscFree(mesh->parents)); 2485 PetscCall(PetscFree(mesh->childIDs)); 2486 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2487 PetscCall(PetscFree(mesh->children)); 2488 PetscCall(DMDestroy(&mesh->referenceTree)); 2489 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2490 PetscCall(PetscFree(mesh->neighbors)); 2491 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2492 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2493 PetscCall(PetscFree(mesh)); 2494 PetscFunctionReturn(0); 2495 } 2496 2497 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2498 { 2499 PetscSection sectionGlobal; 2500 PetscInt bs = -1, mbs; 2501 PetscInt localSize, localStart = 0; 2502 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2503 MatType mtype; 2504 ISLocalToGlobalMapping ltog; 2505 2506 PetscFunctionBegin; 2507 PetscCall(MatInitializePackage()); 2508 mtype = dm->mattype; 2509 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2510 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2511 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2512 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2513 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2514 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2515 PetscCall(MatSetType(*J, mtype)); 2516 PetscCall(MatSetFromOptions(*J)); 2517 PetscCall(MatGetBlockSize(*J, &mbs)); 2518 if (mbs > 1) bs = mbs; 2519 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2520 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2522 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2523 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2524 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2525 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2526 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2527 if (!isShell) { 2528 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2529 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2530 PetscInt pStart, pEnd, p, dof, cdof; 2531 2532 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2533 2534 PetscCall(PetscCalloc1(localSize, &pblocks)); 2535 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2536 for (p = pStart; p < pEnd; ++p) { 2537 PetscInt bdof, offset; 2538 2539 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2540 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2541 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2542 for (PetscInt i=0; i < dof - cdof; i++) 2543 pblocks[offset - localStart + i] = dof - cdof; 2544 dof = dof < 0 ? -(dof+1) : dof; 2545 bdof = cdof && (dof-cdof) ? 1 : dof; 2546 if (dof) { 2547 if (bs < 0) {bs = bdof;} 2548 else if (bs != bdof) {bs = 1;} 2549 } 2550 } 2551 /* Must have same blocksize on all procs (some might have no points) */ 2552 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2553 bsLocal[1] = bs; 2554 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2555 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2556 else bs = bsMinMax[0]; 2557 bs = PetscMax(1,bs); 2558 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2559 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2560 PetscCall(MatSetBlockSize(*J, bs)); 2561 PetscCall(MatSetUp(*J)); 2562 } else { 2563 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2564 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2565 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2566 } 2567 { // Consolidate blocks 2568 PetscInt nblocks = 0; 2569 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2570 if (pblocks[i] == 0) continue; 2571 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2572 for (PetscInt j=1; j<pblocks[i]; j++) { 2573 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]); 2574 } 2575 } 2576 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2577 } 2578 PetscCall(PetscFree(pblocks)); 2579 } 2580 PetscCall(MatSetDM(*J, dm)); 2581 PetscFunctionReturn(0); 2582 } 2583 2584 /*@ 2585 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2586 2587 Not collective 2588 2589 Input Parameter: 2590 . mesh - The DMPlex 2591 2592 Output Parameters: 2593 . subsection - The subdomain section 2594 2595 Level: developer 2596 2597 .seealso: 2598 @*/ 2599 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2600 { 2601 DM_Plex *mesh = (DM_Plex*) dm->data; 2602 2603 PetscFunctionBegin; 2604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2605 if (!mesh->subdomainSection) { 2606 PetscSection section; 2607 PetscSF sf; 2608 2609 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2610 PetscCall(DMGetLocalSection(dm,§ion)); 2611 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2612 PetscCall(PetscSFDestroy(&sf)); 2613 } 2614 *subsection = mesh->subdomainSection; 2615 PetscFunctionReturn(0); 2616 } 2617 2618 /*@ 2619 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2620 2621 Not collective 2622 2623 Input Parameter: 2624 . mesh - The DMPlex 2625 2626 Output Parameters: 2627 + pStart - The first mesh point 2628 - pEnd - The upper bound for mesh points 2629 2630 Level: beginner 2631 2632 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2633 @*/ 2634 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2635 { 2636 DM_Plex *mesh = (DM_Plex*) dm->data; 2637 2638 PetscFunctionBegin; 2639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2640 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2641 PetscFunctionReturn(0); 2642 } 2643 2644 /*@ 2645 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2646 2647 Not collective 2648 2649 Input Parameters: 2650 + mesh - The DMPlex 2651 . pStart - The first mesh point 2652 - pEnd - The upper bound for mesh points 2653 2654 Output Parameters: 2655 2656 Level: beginner 2657 2658 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2659 @*/ 2660 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2661 { 2662 DM_Plex *mesh = (DM_Plex*) dm->data; 2663 2664 PetscFunctionBegin; 2665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2666 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2667 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2668 PetscFunctionReturn(0); 2669 } 2670 2671 /*@ 2672 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2673 2674 Not collective 2675 2676 Input Parameters: 2677 + mesh - The DMPlex 2678 - p - The point, which must lie in the chart set with DMPlexSetChart() 2679 2680 Output Parameter: 2681 . size - The cone size for point p 2682 2683 Level: beginner 2684 2685 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2686 @*/ 2687 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2688 { 2689 DM_Plex *mesh = (DM_Plex*) dm->data; 2690 2691 PetscFunctionBegin; 2692 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2693 PetscValidIntPointer(size, 3); 2694 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2695 PetscFunctionReturn(0); 2696 } 2697 2698 /*@ 2699 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2700 2701 Not collective 2702 2703 Input Parameters: 2704 + mesh - The DMPlex 2705 . p - The point, which must lie in the chart set with DMPlexSetChart() 2706 - size - The cone size for point p 2707 2708 Output Parameter: 2709 2710 Note: 2711 This should be called after DMPlexSetChart(). 2712 2713 Level: beginner 2714 2715 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2716 @*/ 2717 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2718 { 2719 DM_Plex *mesh = (DM_Plex*) dm->data; 2720 2721 PetscFunctionBegin; 2722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2723 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2724 PetscFunctionReturn(0); 2725 } 2726 2727 /*@ 2728 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2729 2730 Not collective 2731 2732 Input Parameters: 2733 + mesh - The DMPlex 2734 . p - The point, which must lie in the chart set with DMPlexSetChart() 2735 - size - The additional cone size for point p 2736 2737 Output Parameter: 2738 2739 Note: 2740 This should be called after DMPlexSetChart(). 2741 2742 Level: beginner 2743 2744 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2745 @*/ 2746 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2747 { 2748 DM_Plex *mesh = (DM_Plex*) dm->data; 2749 PetscFunctionBegin; 2750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2751 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2752 PetscFunctionReturn(0); 2753 } 2754 2755 /*@C 2756 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2757 2758 Not collective 2759 2760 Input Parameters: 2761 + dm - The DMPlex 2762 - p - The point, which must lie in the chart set with DMPlexSetChart() 2763 2764 Output Parameter: 2765 . cone - An array of points which are on the in-edges for point p 2766 2767 Level: beginner 2768 2769 Fortran Notes: 2770 Since it returns an array, this routine is only available in Fortran 90, and you must 2771 include petsc.h90 in your code. 2772 You must also call DMPlexRestoreCone() after you finish using the returned array. 2773 DMPlexRestoreCone() is not needed/available in C. 2774 2775 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2776 @*/ 2777 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2778 { 2779 DM_Plex *mesh = (DM_Plex*) dm->data; 2780 PetscInt off; 2781 2782 PetscFunctionBegin; 2783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2784 PetscValidPointer(cone, 3); 2785 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2786 *cone = &mesh->cones[off]; 2787 PetscFunctionReturn(0); 2788 } 2789 2790 /*@C 2791 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2792 2793 Not collective 2794 2795 Input Parameters: 2796 + dm - The DMPlex 2797 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2798 2799 Output Parameters: 2800 + pConesSection - PetscSection describing the layout of pCones 2801 - pCones - An array of points which are on the in-edges for the point set p 2802 2803 Level: intermediate 2804 2805 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2806 @*/ 2807 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2808 { 2809 PetscSection cs, newcs; 2810 PetscInt *cones; 2811 PetscInt *newarr=NULL; 2812 PetscInt n; 2813 2814 PetscFunctionBegin; 2815 PetscCall(DMPlexGetCones(dm, &cones)); 2816 PetscCall(DMPlexGetConeSection(dm, &cs)); 2817 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2818 if (pConesSection) *pConesSection = newcs; 2819 if (pCones) { 2820 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2821 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2822 } 2823 PetscFunctionReturn(0); 2824 } 2825 2826 /*@ 2827 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2828 2829 Not collective 2830 2831 Input Parameters: 2832 + dm - The DMPlex 2833 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2834 2835 Output Parameter: 2836 . expandedPoints - An array of vertices recursively expanded from input points 2837 2838 Level: advanced 2839 2840 Notes: 2841 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2842 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2843 2844 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2845 @*/ 2846 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2847 { 2848 IS *expandedPointsAll; 2849 PetscInt depth; 2850 2851 PetscFunctionBegin; 2852 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2853 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2854 PetscValidPointer(expandedPoints, 3); 2855 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2856 *expandedPoints = expandedPointsAll[0]; 2857 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2858 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2859 PetscFunctionReturn(0); 2860 } 2861 2862 /*@ 2863 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). 2864 2865 Not collective 2866 2867 Input Parameters: 2868 + dm - The DMPlex 2869 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2870 2871 Output Parameters: 2872 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2873 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2874 - sections - (optional) An array of sections which describe mappings from points to their cone points 2875 2876 Level: advanced 2877 2878 Notes: 2879 Like DMPlexGetConeTuple() but recursive. 2880 2881 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. 2882 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2883 2884 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: 2885 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2886 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2887 2888 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2889 @*/ 2890 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2891 { 2892 const PetscInt *arr0=NULL, *cone=NULL; 2893 PetscInt *arr=NULL, *newarr=NULL; 2894 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2895 IS *expandedPoints_; 2896 PetscSection *sections_; 2897 2898 PetscFunctionBegin; 2899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2900 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2901 if (depth) PetscValidIntPointer(depth, 3); 2902 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2903 if (sections) PetscValidPointer(sections, 5); 2904 PetscCall(ISGetLocalSize(points, &n)); 2905 PetscCall(ISGetIndices(points, &arr0)); 2906 PetscCall(DMPlexGetDepth(dm, &depth_)); 2907 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2908 PetscCall(PetscCalloc1(depth_, §ions_)); 2909 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2910 for (d=depth_-1; d>=0; d--) { 2911 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2912 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2913 for (i=0; i<n; i++) { 2914 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2915 if (arr[i] >= start && arr[i] < end) { 2916 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2917 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2918 } else { 2919 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2920 } 2921 } 2922 PetscCall(PetscSectionSetUp(sections_[d])); 2923 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2924 PetscCall(PetscMalloc1(newn, &newarr)); 2925 for (i=0; i<n; i++) { 2926 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2927 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2928 if (cn > 1) { 2929 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2930 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2931 } else { 2932 newarr[co] = arr[i]; 2933 } 2934 } 2935 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2936 arr = newarr; 2937 n = newn; 2938 } 2939 PetscCall(ISRestoreIndices(points, &arr0)); 2940 *depth = depth_; 2941 if (expandedPoints) *expandedPoints = expandedPoints_; 2942 else { 2943 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2944 PetscCall(PetscFree(expandedPoints_)); 2945 } 2946 if (sections) *sections = sections_; 2947 else { 2948 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2949 PetscCall(PetscFree(sections_)); 2950 } 2951 PetscFunctionReturn(0); 2952 } 2953 2954 /*@ 2955 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2956 2957 Not collective 2958 2959 Input Parameters: 2960 + dm - The DMPlex 2961 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2962 2963 Output Parameters: 2964 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2965 . expandedPoints - (optional) An array of recursively expanded cones 2966 - sections - (optional) An array of sections which describe mappings from points to their cone points 2967 2968 Level: advanced 2969 2970 Notes: 2971 See DMPlexGetConeRecursive() for details. 2972 2973 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2974 @*/ 2975 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2976 { 2977 PetscInt d, depth_; 2978 2979 PetscFunctionBegin; 2980 PetscCall(DMPlexGetDepth(dm, &depth_)); 2981 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2982 if (depth) *depth = 0; 2983 if (expandedPoints) { 2984 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2985 PetscCall(PetscFree(*expandedPoints)); 2986 } 2987 if (sections) { 2988 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2989 PetscCall(PetscFree(*sections)); 2990 } 2991 PetscFunctionReturn(0); 2992 } 2993 2994 /*@ 2995 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 2996 2997 Not collective 2998 2999 Input Parameters: 3000 + mesh - The DMPlex 3001 . p - The point, which must lie in the chart set with DMPlexSetChart() 3002 - cone - An array of points which are on the in-edges for point p 3003 3004 Output Parameter: 3005 3006 Note: 3007 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3008 3009 Level: beginner 3010 3011 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3012 @*/ 3013 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3014 { 3015 DM_Plex *mesh = (DM_Plex*) dm->data; 3016 PetscInt pStart, pEnd; 3017 PetscInt dof, off, c; 3018 3019 PetscFunctionBegin; 3020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3021 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3022 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3023 if (dof) PetscValidIntPointer(cone, 3); 3024 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3025 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); 3026 for (c = 0; c < dof; ++c) { 3027 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); 3028 mesh->cones[off+c] = cone[c]; 3029 } 3030 PetscFunctionReturn(0); 3031 } 3032 3033 /*@C 3034 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3035 3036 Not collective 3037 3038 Input Parameters: 3039 + mesh - The DMPlex 3040 - p - The point, which must lie in the chart set with DMPlexSetChart() 3041 3042 Output Parameter: 3043 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3044 integer giving the prescription for cone traversal. 3045 3046 Level: beginner 3047 3048 Notes: 3049 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3050 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3051 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3052 with the identity. 3053 3054 Fortran Notes: 3055 Since it returns an array, this routine is only available in Fortran 90, and you must 3056 include petsc.h90 in your code. 3057 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3058 DMPlexRestoreConeOrientation() is not needed/available in C. 3059 3060 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3061 @*/ 3062 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3063 { 3064 DM_Plex *mesh = (DM_Plex*) dm->data; 3065 PetscInt off; 3066 3067 PetscFunctionBegin; 3068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3069 if (PetscDefined(USE_DEBUG)) { 3070 PetscInt dof; 3071 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3072 if (dof) PetscValidPointer(coneOrientation, 3); 3073 } 3074 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3075 3076 *coneOrientation = &mesh->coneOrientations[off]; 3077 PetscFunctionReturn(0); 3078 } 3079 3080 /*@ 3081 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3082 3083 Not collective 3084 3085 Input Parameters: 3086 + mesh - The DMPlex 3087 . p - The point, which must lie in the chart set with DMPlexSetChart() 3088 - coneOrientation - An array of orientations 3089 Output Parameter: 3090 3091 Notes: 3092 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3093 3094 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3095 3096 Level: beginner 3097 3098 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3099 @*/ 3100 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3101 { 3102 DM_Plex *mesh = (DM_Plex*) dm->data; 3103 PetscInt pStart, pEnd; 3104 PetscInt dof, off, c; 3105 3106 PetscFunctionBegin; 3107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3108 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3109 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3110 if (dof) PetscValidIntPointer(coneOrientation, 3); 3111 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3112 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); 3113 for (c = 0; c < dof; ++c) { 3114 PetscInt cdof, o = coneOrientation[c]; 3115 3116 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3117 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); 3118 mesh->coneOrientations[off+c] = o; 3119 } 3120 PetscFunctionReturn(0); 3121 } 3122 3123 /*@ 3124 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3125 3126 Not collective 3127 3128 Input Parameters: 3129 + mesh - The DMPlex 3130 . p - The point, which must lie in the chart set with DMPlexSetChart() 3131 . conePos - The local index in the cone where the point should be put 3132 - conePoint - The mesh point to insert 3133 3134 Level: beginner 3135 3136 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3137 @*/ 3138 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3139 { 3140 DM_Plex *mesh = (DM_Plex*) dm->data; 3141 PetscInt pStart, pEnd; 3142 PetscInt dof, off; 3143 3144 PetscFunctionBegin; 3145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3146 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3147 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); 3148 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); 3149 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3150 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3151 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); 3152 mesh->cones[off+conePos] = conePoint; 3153 PetscFunctionReturn(0); 3154 } 3155 3156 /*@ 3157 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3158 3159 Not collective 3160 3161 Input Parameters: 3162 + mesh - The DMPlex 3163 . p - The point, which must lie in the chart set with DMPlexSetChart() 3164 . conePos - The local index in the cone where the point should be put 3165 - coneOrientation - The point orientation to insert 3166 3167 Level: beginner 3168 3169 Notes: 3170 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3171 3172 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3173 @*/ 3174 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3175 { 3176 DM_Plex *mesh = (DM_Plex*) dm->data; 3177 PetscInt pStart, pEnd; 3178 PetscInt dof, off; 3179 3180 PetscFunctionBegin; 3181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3182 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3183 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); 3184 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3185 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3186 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); 3187 mesh->coneOrientations[off+conePos] = coneOrientation; 3188 PetscFunctionReturn(0); 3189 } 3190 3191 /*@ 3192 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3193 3194 Not collective 3195 3196 Input Parameters: 3197 + mesh - The DMPlex 3198 - p - The point, which must lie in the chart set with DMPlexSetChart() 3199 3200 Output Parameter: 3201 . size - The support size for point p 3202 3203 Level: beginner 3204 3205 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3206 @*/ 3207 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3208 { 3209 DM_Plex *mesh = (DM_Plex*) dm->data; 3210 3211 PetscFunctionBegin; 3212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3213 PetscValidIntPointer(size, 3); 3214 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3215 PetscFunctionReturn(0); 3216 } 3217 3218 /*@ 3219 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3220 3221 Not collective 3222 3223 Input Parameters: 3224 + mesh - The DMPlex 3225 . p - The point, which must lie in the chart set with DMPlexSetChart() 3226 - size - The support size for point p 3227 3228 Output Parameter: 3229 3230 Note: 3231 This should be called after DMPlexSetChart(). 3232 3233 Level: beginner 3234 3235 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3236 @*/ 3237 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3238 { 3239 DM_Plex *mesh = (DM_Plex*) dm->data; 3240 3241 PetscFunctionBegin; 3242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3243 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3244 PetscFunctionReturn(0); 3245 } 3246 3247 /*@C 3248 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3249 3250 Not collective 3251 3252 Input Parameters: 3253 + mesh - The DMPlex 3254 - p - The point, which must lie in the chart set with DMPlexSetChart() 3255 3256 Output Parameter: 3257 . support - An array of points which are on the out-edges for point p 3258 3259 Level: beginner 3260 3261 Fortran Notes: 3262 Since it returns an array, this routine is only available in Fortran 90, and you must 3263 include petsc.h90 in your code. 3264 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3265 DMPlexRestoreSupport() is not needed/available in C. 3266 3267 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3268 @*/ 3269 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3270 { 3271 DM_Plex *mesh = (DM_Plex*) dm->data; 3272 PetscInt off; 3273 3274 PetscFunctionBegin; 3275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3276 PetscValidPointer(support, 3); 3277 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3278 *support = &mesh->supports[off]; 3279 PetscFunctionReturn(0); 3280 } 3281 3282 /*@ 3283 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3284 3285 Not collective 3286 3287 Input Parameters: 3288 + mesh - The DMPlex 3289 . p - The point, which must lie in the chart set with DMPlexSetChart() 3290 - support - An array of points which are on the out-edges for point p 3291 3292 Output Parameter: 3293 3294 Note: 3295 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3296 3297 Level: beginner 3298 3299 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3300 @*/ 3301 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3302 { 3303 DM_Plex *mesh = (DM_Plex*) dm->data; 3304 PetscInt pStart, pEnd; 3305 PetscInt dof, off, c; 3306 3307 PetscFunctionBegin; 3308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3309 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3310 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3311 if (dof) PetscValidIntPointer(support, 3); 3312 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3313 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); 3314 for (c = 0; c < dof; ++c) { 3315 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); 3316 mesh->supports[off+c] = support[c]; 3317 } 3318 PetscFunctionReturn(0); 3319 } 3320 3321 /*@ 3322 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3323 3324 Not collective 3325 3326 Input Parameters: 3327 + mesh - The DMPlex 3328 . p - The point, which must lie in the chart set with DMPlexSetChart() 3329 . supportPos - The local index in the cone where the point should be put 3330 - supportPoint - The mesh point to insert 3331 3332 Level: beginner 3333 3334 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3335 @*/ 3336 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3337 { 3338 DM_Plex *mesh = (DM_Plex*) dm->data; 3339 PetscInt pStart, pEnd; 3340 PetscInt dof, off; 3341 3342 PetscFunctionBegin; 3343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3344 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3345 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3346 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3347 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); 3348 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); 3349 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); 3350 mesh->supports[off+supportPos] = supportPoint; 3351 PetscFunctionReturn(0); 3352 } 3353 3354 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3355 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3356 { 3357 switch (ct) { 3358 case DM_POLYTOPE_SEGMENT: 3359 if (o == -1) return -2; 3360 break; 3361 case DM_POLYTOPE_TRIANGLE: 3362 if (o == -3) return -1; 3363 if (o == -2) return -3; 3364 if (o == -1) return -2; 3365 break; 3366 case DM_POLYTOPE_QUADRILATERAL: 3367 if (o == -4) return -2; 3368 if (o == -3) return -1; 3369 if (o == -2) return -4; 3370 if (o == -1) return -3; 3371 break; 3372 default: return o; 3373 } 3374 return o; 3375 } 3376 3377 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3378 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3379 { 3380 switch (ct) { 3381 case DM_POLYTOPE_SEGMENT: 3382 if ((o == -2) || (o == 1)) return -1; 3383 if (o == -1) return 0; 3384 break; 3385 case DM_POLYTOPE_TRIANGLE: 3386 if (o == -3) return -2; 3387 if (o == -2) return -1; 3388 if (o == -1) return -3; 3389 break; 3390 case DM_POLYTOPE_QUADRILATERAL: 3391 if (o == -4) return -2; 3392 if (o == -3) return -1; 3393 if (o == -2) return -4; 3394 if (o == -1) return -3; 3395 break; 3396 default: return o; 3397 } 3398 return o; 3399 } 3400 3401 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3402 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3403 { 3404 PetscInt pStart, pEnd, p; 3405 3406 PetscFunctionBegin; 3407 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3408 for (p = pStart; p < pEnd; ++p) { 3409 const PetscInt *cone, *ornt; 3410 PetscInt coneSize, c; 3411 3412 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3413 PetscCall(DMPlexGetCone(dm, p, &cone)); 3414 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3415 for (c = 0; c < coneSize; ++c) { 3416 DMPolytopeType ct; 3417 const PetscInt o = ornt[c]; 3418 3419 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3420 switch (ct) { 3421 case DM_POLYTOPE_SEGMENT: 3422 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3423 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3424 break; 3425 case DM_POLYTOPE_TRIANGLE: 3426 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3427 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3428 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3429 break; 3430 case DM_POLYTOPE_QUADRILATERAL: 3431 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3432 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3433 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3434 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3435 break; 3436 default: break; 3437 } 3438 } 3439 } 3440 PetscFunctionReturn(0); 3441 } 3442 3443 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3444 { 3445 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3446 PetscInt *closure; 3447 const PetscInt *tmp = NULL, *tmpO = NULL; 3448 PetscInt off = 0, tmpSize, t; 3449 3450 PetscFunctionBeginHot; 3451 if (ornt) { 3452 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3453 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3454 } 3455 if (*points) { 3456 closure = *points; 3457 } else { 3458 PetscInt maxConeSize, maxSupportSize; 3459 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3460 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3461 } 3462 if (useCone) { 3463 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3464 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3465 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3466 } else { 3467 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3468 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3469 } 3470 if (ct == DM_POLYTOPE_UNKNOWN) { 3471 closure[off++] = p; 3472 closure[off++] = 0; 3473 for (t = 0; t < tmpSize; ++t) { 3474 closure[off++] = tmp[t]; 3475 closure[off++] = tmpO ? tmpO[t] : 0; 3476 } 3477 } else { 3478 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3479 3480 /* We assume that cells with a valid type have faces with a valid type */ 3481 closure[off++] = p; 3482 closure[off++] = ornt; 3483 for (t = 0; t < tmpSize; ++t) { 3484 DMPolytopeType ft; 3485 3486 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3487 closure[off++] = tmp[arr[t]]; 3488 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3489 } 3490 } 3491 if (numPoints) *numPoints = tmpSize+1; 3492 if (points) *points = closure; 3493 PetscFunctionReturn(0); 3494 } 3495 3496 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3497 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3498 { 3499 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3500 const PetscInt *cone, *ornt; 3501 PetscInt *pts, *closure = NULL; 3502 DMPolytopeType ft; 3503 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3504 PetscInt dim, coneSize, c, d, clSize, cl; 3505 3506 PetscFunctionBeginHot; 3507 PetscCall(DMGetDimension(dm, &dim)); 3508 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3509 PetscCall(DMPlexGetCone(dm, point, &cone)); 3510 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3511 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3512 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3513 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3514 maxSize = PetscMax(coneSeries, supportSeries); 3515 if (*points) {pts = *points;} 3516 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3517 c = 0; 3518 pts[c++] = point; 3519 pts[c++] = o; 3520 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3521 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3522 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3523 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3524 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3525 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3526 for (d = 2; d < coneSize; ++d) { 3527 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3528 pts[c++] = cone[arr[d*2+0]]; 3529 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3530 } 3531 if (dim >= 3) { 3532 for (d = 2; d < coneSize; ++d) { 3533 const PetscInt fpoint = cone[arr[d*2+0]]; 3534 const PetscInt *fcone, *fornt; 3535 PetscInt fconeSize, fc, i; 3536 3537 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3538 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3539 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3540 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3541 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3542 for (fc = 0; fc < fconeSize; ++fc) { 3543 const PetscInt cp = fcone[farr[fc*2+0]]; 3544 const PetscInt co = farr[fc*2+1]; 3545 3546 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3547 if (i == c) { 3548 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3549 pts[c++] = cp; 3550 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3551 } 3552 } 3553 } 3554 } 3555 *numPoints = c/2; 3556 *points = pts; 3557 PetscFunctionReturn(0); 3558 } 3559 3560 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3561 { 3562 DMPolytopeType ct; 3563 PetscInt *closure, *fifo; 3564 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3565 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3566 PetscInt depth, maxSize; 3567 3568 PetscFunctionBeginHot; 3569 PetscCall(DMPlexGetDepth(dm, &depth)); 3570 if (depth == 1) { 3571 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3572 PetscFunctionReturn(0); 3573 } 3574 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3575 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3576 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3577 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3578 PetscFunctionReturn(0); 3579 } 3580 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3581 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3582 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3583 maxSize = PetscMax(coneSeries, supportSeries); 3584 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3585 if (*points) {closure = *points;} 3586 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3587 closure[closureSize++] = p; 3588 closure[closureSize++] = ornt; 3589 fifo[fifoSize++] = p; 3590 fifo[fifoSize++] = ornt; 3591 fifo[fifoSize++] = ct; 3592 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3593 while (fifoSize - fifoStart) { 3594 const PetscInt q = fifo[fifoStart++]; 3595 const PetscInt o = fifo[fifoStart++]; 3596 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3597 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3598 const PetscInt *tmp, *tmpO; 3599 PetscInt tmpSize, t; 3600 3601 if (PetscDefined(USE_DEBUG)) { 3602 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3603 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); 3604 } 3605 if (useCone) { 3606 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3607 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3608 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3609 } else { 3610 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3611 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3612 tmpO = NULL; 3613 } 3614 for (t = 0; t < tmpSize; ++t) { 3615 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3616 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3617 const PetscInt cp = tmp[ip]; 3618 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3619 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3620 PetscInt c; 3621 3622 /* Check for duplicate */ 3623 for (c = 0; c < closureSize; c += 2) { 3624 if (closure[c] == cp) break; 3625 } 3626 if (c == closureSize) { 3627 closure[closureSize++] = cp; 3628 closure[closureSize++] = co; 3629 fifo[fifoSize++] = cp; 3630 fifo[fifoSize++] = co; 3631 fifo[fifoSize++] = ct; 3632 } 3633 } 3634 } 3635 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3636 if (numPoints) *numPoints = closureSize/2; 3637 if (points) *points = closure; 3638 PetscFunctionReturn(0); 3639 } 3640 3641 /*@C 3642 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3643 3644 Not collective 3645 3646 Input Parameters: 3647 + dm - The DMPlex 3648 . p - The mesh point 3649 - useCone - PETSC_TRUE for the closure, otherwise return the star 3650 3651 Input/Output Parameter: 3652 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3653 if NULL on input, internal storage will be returned, otherwise the provided array is used 3654 3655 Output Parameter: 3656 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3657 3658 Note: 3659 If using internal storage (points is NULL on input), each call overwrites the last output. 3660 3661 Fortran Notes: 3662 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3663 3664 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3665 3666 Level: beginner 3667 3668 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3669 @*/ 3670 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3671 { 3672 PetscFunctionBeginHot; 3673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3674 if (numPoints) PetscValidIntPointer(numPoints, 4); 3675 if (points) PetscValidPointer(points, 5); 3676 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3677 PetscFunctionReturn(0); 3678 } 3679 3680 /*@C 3681 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3682 3683 Not collective 3684 3685 Input Parameters: 3686 + dm - The DMPlex 3687 . p - The mesh point 3688 . useCone - PETSC_TRUE for the closure, otherwise return the star 3689 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3690 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3691 3692 Note: 3693 If not using internal storage (points is not NULL on input), this call is unnecessary 3694 3695 Fortran Notes: 3696 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3697 3698 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3699 3700 Level: beginner 3701 3702 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3703 @*/ 3704 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3705 { 3706 PetscFunctionBeginHot; 3707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3708 if (numPoints) *numPoints = 0; 3709 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3710 PetscFunctionReturn(0); 3711 } 3712 3713 /*@ 3714 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3715 3716 Not collective 3717 3718 Input Parameter: 3719 . mesh - The DMPlex 3720 3721 Output Parameters: 3722 + maxConeSize - The maximum number of in-edges 3723 - maxSupportSize - The maximum number of out-edges 3724 3725 Level: beginner 3726 3727 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3728 @*/ 3729 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3730 { 3731 DM_Plex *mesh = (DM_Plex*) dm->data; 3732 3733 PetscFunctionBegin; 3734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3735 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3736 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3737 PetscFunctionReturn(0); 3738 } 3739 3740 PetscErrorCode DMSetUp_Plex(DM dm) 3741 { 3742 DM_Plex *mesh = (DM_Plex*) dm->data; 3743 PetscInt size, maxSupportSize; 3744 3745 PetscFunctionBegin; 3746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3747 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3748 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3749 PetscCall(PetscMalloc1(size, &mesh->cones)); 3750 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3751 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3752 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3753 if (maxSupportSize) { 3754 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3755 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3756 PetscCall(PetscMalloc1(size, &mesh->supports)); 3757 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3758 } 3759 PetscFunctionReturn(0); 3760 } 3761 3762 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3763 { 3764 PetscFunctionBegin; 3765 if (subdm) PetscCall(DMClone(dm, subdm)); 3766 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3767 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3768 if (dm->useNatural && dm->sfMigration) { 3769 PetscSF sfMigrationInv,sfNatural; 3770 PetscSection section, sectionSeq; 3771 3772 (*subdm)->sfMigration = dm->sfMigration; 3773 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3774 PetscCall(DMGetLocalSection((*subdm), §ion)); 3775 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3776 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3777 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3778 3779 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3780 (*subdm)->sfNatural = sfNatural; 3781 PetscCall(PetscSectionDestroy(§ionSeq)); 3782 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3783 } 3784 PetscFunctionReturn(0); 3785 } 3786 3787 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3788 { 3789 PetscInt i = 0; 3790 3791 PetscFunctionBegin; 3792 PetscCall(DMClone(dms[0], superdm)); 3793 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3794 (*superdm)->useNatural = PETSC_FALSE; 3795 for (i = 0; i < len; i++) { 3796 if (dms[i]->useNatural && dms[i]->sfMigration) { 3797 PetscSF sfMigrationInv,sfNatural; 3798 PetscSection section, sectionSeq; 3799 3800 (*superdm)->sfMigration = dms[i]->sfMigration; 3801 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3802 (*superdm)->useNatural = PETSC_TRUE; 3803 PetscCall(DMGetLocalSection((*superdm), §ion)); 3804 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3805 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3806 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3807 3808 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3809 (*superdm)->sfNatural = sfNatural; 3810 PetscCall(PetscSectionDestroy(§ionSeq)); 3811 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3812 break; 3813 } 3814 } 3815 PetscFunctionReturn(0); 3816 } 3817 3818 /*@ 3819 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3820 3821 Not collective 3822 3823 Input Parameter: 3824 . mesh - The DMPlex 3825 3826 Output Parameter: 3827 3828 Note: 3829 This should be called after all calls to DMPlexSetCone() 3830 3831 Level: beginner 3832 3833 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3834 @*/ 3835 PetscErrorCode DMPlexSymmetrize(DM dm) 3836 { 3837 DM_Plex *mesh = (DM_Plex*) dm->data; 3838 PetscInt *offsets; 3839 PetscInt supportSize; 3840 PetscInt pStart, pEnd, p; 3841 3842 PetscFunctionBegin; 3843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3844 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3845 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3846 /* Calculate support sizes */ 3847 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3848 for (p = pStart; p < pEnd; ++p) { 3849 PetscInt dof, off, c; 3850 3851 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3852 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3853 for (c = off; c < off+dof; ++c) { 3854 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3855 } 3856 } 3857 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3858 /* Calculate supports */ 3859 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3860 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3861 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3862 for (p = pStart; p < pEnd; ++p) { 3863 PetscInt dof, off, c; 3864 3865 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3866 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3867 for (c = off; c < off+dof; ++c) { 3868 const PetscInt q = mesh->cones[c]; 3869 PetscInt offS; 3870 3871 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3872 3873 mesh->supports[offS+offsets[q]] = p; 3874 ++offsets[q]; 3875 } 3876 } 3877 PetscCall(PetscFree(offsets)); 3878 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3879 PetscFunctionReturn(0); 3880 } 3881 3882 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3883 { 3884 IS stratumIS; 3885 3886 PetscFunctionBegin; 3887 if (pStart >= pEnd) PetscFunctionReturn(0); 3888 if (PetscDefined(USE_DEBUG)) { 3889 PetscInt qStart, qEnd, numLevels, level; 3890 PetscBool overlap = PETSC_FALSE; 3891 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3892 for (level = 0; level < numLevels; level++) { 3893 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3894 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3895 } 3896 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); 3897 } 3898 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3899 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3900 PetscCall(ISDestroy(&stratumIS)); 3901 PetscFunctionReturn(0); 3902 } 3903 3904 /*@ 3905 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3906 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3907 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3908 the DAG. 3909 3910 Collective on dm 3911 3912 Input Parameter: 3913 . mesh - The DMPlex 3914 3915 Output Parameter: 3916 3917 Notes: 3918 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3919 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3920 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3921 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3922 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3923 3924 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3925 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3926 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 3927 to interpolate only that one (e0), so that 3928 $ cone(c0) = {e0, v2} 3929 $ cone(e0) = {v0, v1} 3930 If DMPlexStratify() is run on this mesh, it will give depths 3931 $ depth 0 = {v0, v1, v2} 3932 $ depth 1 = {e0, c0} 3933 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3934 3935 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3936 3937 Level: beginner 3938 3939 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3940 @*/ 3941 PetscErrorCode DMPlexStratify(DM dm) 3942 { 3943 DM_Plex *mesh = (DM_Plex*) dm->data; 3944 DMLabel label; 3945 PetscInt pStart, pEnd, p; 3946 PetscInt numRoots = 0, numLeaves = 0; 3947 3948 PetscFunctionBegin; 3949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3950 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3951 3952 /* Create depth label */ 3953 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3954 PetscCall(DMCreateLabel(dm, "depth")); 3955 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3956 3957 { 3958 /* Initialize roots and count leaves */ 3959 PetscInt sMin = PETSC_MAX_INT; 3960 PetscInt sMax = PETSC_MIN_INT; 3961 PetscInt coneSize, supportSize; 3962 3963 for (p = pStart; p < pEnd; ++p) { 3964 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3965 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3966 if (!coneSize && supportSize) { 3967 sMin = PetscMin(p, sMin); 3968 sMax = PetscMax(p, sMax); 3969 ++numRoots; 3970 } else if (!supportSize && coneSize) { 3971 ++numLeaves; 3972 } else if (!supportSize && !coneSize) { 3973 /* Isolated points */ 3974 sMin = PetscMin(p, sMin); 3975 sMax = PetscMax(p, sMax); 3976 } 3977 } 3978 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3979 } 3980 3981 if (numRoots + numLeaves == (pEnd - pStart)) { 3982 PetscInt sMin = PETSC_MAX_INT; 3983 PetscInt sMax = PETSC_MIN_INT; 3984 PetscInt coneSize, supportSize; 3985 3986 for (p = pStart; p < pEnd; ++p) { 3987 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3988 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3989 if (!supportSize && coneSize) { 3990 sMin = PetscMin(p, sMin); 3991 sMax = PetscMax(p, sMax); 3992 } 3993 } 3994 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3995 } else { 3996 PetscInt level = 0; 3997 PetscInt qStart, qEnd, q; 3998 3999 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4000 while (qEnd > qStart) { 4001 PetscInt sMin = PETSC_MAX_INT; 4002 PetscInt sMax = PETSC_MIN_INT; 4003 4004 for (q = qStart; q < qEnd; ++q) { 4005 const PetscInt *support; 4006 PetscInt supportSize, s; 4007 4008 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4009 PetscCall(DMPlexGetSupport(dm, q, &support)); 4010 for (s = 0; s < supportSize; ++s) { 4011 sMin = PetscMin(support[s], sMin); 4012 sMax = PetscMax(support[s], sMax); 4013 } 4014 } 4015 PetscCall(DMLabelGetNumValues(label, &level)); 4016 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4017 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4018 } 4019 } 4020 { /* just in case there is an empty process */ 4021 PetscInt numValues, maxValues = 0, v; 4022 4023 PetscCall(DMLabelGetNumValues(label, &numValues)); 4024 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4025 for (v = numValues; v < maxValues; v++) { 4026 PetscCall(DMLabelAddStratum(label, v)); 4027 } 4028 } 4029 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4030 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4031 PetscFunctionReturn(0); 4032 } 4033 4034 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4035 { 4036 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4037 PetscInt dim, depth, pheight, coneSize; 4038 4039 PetscFunctionBeginHot; 4040 PetscCall(DMGetDimension(dm, &dim)); 4041 PetscCall(DMPlexGetDepth(dm, &depth)); 4042 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4043 pheight = depth - pdepth; 4044 if (depth <= 1) { 4045 switch (pdepth) { 4046 case 0: ct = DM_POLYTOPE_POINT;break; 4047 case 1: 4048 switch (coneSize) { 4049 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4050 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4051 case 4: 4052 switch (dim) { 4053 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4054 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4055 default: break; 4056 } 4057 break; 4058 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4059 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4060 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4061 default: break; 4062 } 4063 } 4064 } else { 4065 if (pdepth == 0) { 4066 ct = DM_POLYTOPE_POINT; 4067 } else if (pheight == 0) { 4068 switch (dim) { 4069 case 1: 4070 switch (coneSize) { 4071 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4072 default: break; 4073 } 4074 break; 4075 case 2: 4076 switch (coneSize) { 4077 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4078 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4079 default: break; 4080 } 4081 break; 4082 case 3: 4083 switch (coneSize) { 4084 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4085 case 5: 4086 { 4087 const PetscInt *cone; 4088 PetscInt faceConeSize; 4089 4090 PetscCall(DMPlexGetCone(dm, p, &cone)); 4091 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4092 switch (faceConeSize) { 4093 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4094 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4095 } 4096 } 4097 break; 4098 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4099 default: break; 4100 } 4101 break; 4102 default: break; 4103 } 4104 } else if (pheight > 0) { 4105 switch (coneSize) { 4106 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4107 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4108 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4109 default: break; 4110 } 4111 } 4112 } 4113 *pt = ct; 4114 PetscFunctionReturn(0); 4115 } 4116 4117 /*@ 4118 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4119 4120 Collective on dm 4121 4122 Input Parameter: 4123 . mesh - The DMPlex 4124 4125 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4126 4127 Level: developer 4128 4129 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4130 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4131 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4132 4133 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4134 @*/ 4135 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4136 { 4137 DM_Plex *mesh; 4138 DMLabel ctLabel; 4139 PetscInt pStart, pEnd, p; 4140 4141 PetscFunctionBegin; 4142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4143 mesh = (DM_Plex *) dm->data; 4144 PetscCall(DMCreateLabel(dm, "celltype")); 4145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4146 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4147 for (p = pStart; p < pEnd; ++p) { 4148 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4149 PetscInt pdepth; 4150 4151 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4152 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4153 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4154 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4155 } 4156 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4157 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4158 PetscFunctionReturn(0); 4159 } 4160 4161 /*@C 4162 DMPlexGetJoin - Get an array for the join of the set of points 4163 4164 Not Collective 4165 4166 Input Parameters: 4167 + dm - The DMPlex object 4168 . numPoints - The number of input points for the join 4169 - points - The input points 4170 4171 Output Parameters: 4172 + numCoveredPoints - The number of points in the join 4173 - coveredPoints - The points in the join 4174 4175 Level: intermediate 4176 4177 Note: Currently, this is restricted to a single level join 4178 4179 Fortran Notes: 4180 Since it returns an array, this routine is only available in Fortran 90, and you must 4181 include petsc.h90 in your code. 4182 4183 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4184 4185 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4186 @*/ 4187 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4188 { 4189 DM_Plex *mesh = (DM_Plex*) dm->data; 4190 PetscInt *join[2]; 4191 PetscInt joinSize, i = 0; 4192 PetscInt dof, off, p, c, m; 4193 PetscInt maxSupportSize; 4194 4195 PetscFunctionBegin; 4196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4197 PetscValidIntPointer(points, 3); 4198 PetscValidIntPointer(numCoveredPoints, 4); 4199 PetscValidPointer(coveredPoints, 5); 4200 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4201 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4202 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4203 /* Copy in support of first point */ 4204 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4205 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4206 for (joinSize = 0; joinSize < dof; ++joinSize) { 4207 join[i][joinSize] = mesh->supports[off+joinSize]; 4208 } 4209 /* Check each successive support */ 4210 for (p = 1; p < numPoints; ++p) { 4211 PetscInt newJoinSize = 0; 4212 4213 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4214 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4215 for (c = 0; c < dof; ++c) { 4216 const PetscInt point = mesh->supports[off+c]; 4217 4218 for (m = 0; m < joinSize; ++m) { 4219 if (point == join[i][m]) { 4220 join[1-i][newJoinSize++] = point; 4221 break; 4222 } 4223 } 4224 } 4225 joinSize = newJoinSize; 4226 i = 1-i; 4227 } 4228 *numCoveredPoints = joinSize; 4229 *coveredPoints = join[i]; 4230 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4231 PetscFunctionReturn(0); 4232 } 4233 4234 /*@C 4235 DMPlexRestoreJoin - Restore an array for the join of the set of points 4236 4237 Not Collective 4238 4239 Input Parameters: 4240 + dm - The DMPlex object 4241 . numPoints - The number of input points for the join 4242 - points - The input points 4243 4244 Output Parameters: 4245 + numCoveredPoints - The number of points in the join 4246 - coveredPoints - The points in the join 4247 4248 Fortran Notes: 4249 Since it returns an array, this routine is only available in Fortran 90, and you must 4250 include petsc.h90 in your code. 4251 4252 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4253 4254 Level: intermediate 4255 4256 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4257 @*/ 4258 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4259 { 4260 PetscFunctionBegin; 4261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4262 if (points) PetscValidIntPointer(points,3); 4263 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4264 PetscValidPointer(coveredPoints, 5); 4265 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4266 if (numCoveredPoints) *numCoveredPoints = 0; 4267 PetscFunctionReturn(0); 4268 } 4269 4270 /*@C 4271 DMPlexGetFullJoin - Get an array for the join of the set of points 4272 4273 Not Collective 4274 4275 Input Parameters: 4276 + dm - The DMPlex object 4277 . numPoints - The number of input points for the join 4278 - points - The input points 4279 4280 Output Parameters: 4281 + numCoveredPoints - The number of points in the join 4282 - coveredPoints - The points in the join 4283 4284 Fortran Notes: 4285 Since it returns an array, this routine is only available in Fortran 90, and you must 4286 include petsc.h90 in your code. 4287 4288 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4289 4290 Level: intermediate 4291 4292 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4293 @*/ 4294 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4295 { 4296 PetscInt *offsets, **closures; 4297 PetscInt *join[2]; 4298 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4299 PetscInt p, d, c, m, ms; 4300 4301 PetscFunctionBegin; 4302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4303 PetscValidIntPointer(points, 3); 4304 PetscValidIntPointer(numCoveredPoints, 4); 4305 PetscValidPointer(coveredPoints, 5); 4306 4307 PetscCall(DMPlexGetDepth(dm, &depth)); 4308 PetscCall(PetscCalloc1(numPoints, &closures)); 4309 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4310 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4311 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4312 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4313 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4314 4315 for (p = 0; p < numPoints; ++p) { 4316 PetscInt closureSize; 4317 4318 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4319 4320 offsets[p*(depth+2)+0] = 0; 4321 for (d = 0; d < depth+1; ++d) { 4322 PetscInt pStart, pEnd, i; 4323 4324 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4325 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4326 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4327 offsets[p*(depth+2)+d+1] = i; 4328 break; 4329 } 4330 } 4331 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4332 } 4333 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); 4334 } 4335 for (d = 0; d < depth+1; ++d) { 4336 PetscInt dof; 4337 4338 /* Copy in support of first point */ 4339 dof = offsets[d+1] - offsets[d]; 4340 for (joinSize = 0; joinSize < dof; ++joinSize) { 4341 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4342 } 4343 /* Check each successive cone */ 4344 for (p = 1; p < numPoints && joinSize; ++p) { 4345 PetscInt newJoinSize = 0; 4346 4347 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4348 for (c = 0; c < dof; ++c) { 4349 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4350 4351 for (m = 0; m < joinSize; ++m) { 4352 if (point == join[i][m]) { 4353 join[1-i][newJoinSize++] = point; 4354 break; 4355 } 4356 } 4357 } 4358 joinSize = newJoinSize; 4359 i = 1-i; 4360 } 4361 if (joinSize) break; 4362 } 4363 *numCoveredPoints = joinSize; 4364 *coveredPoints = join[i]; 4365 for (p = 0; p < numPoints; ++p) { 4366 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4367 } 4368 PetscCall(PetscFree(closures)); 4369 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4370 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4371 PetscFunctionReturn(0); 4372 } 4373 4374 /*@C 4375 DMPlexGetMeet - Get an array for the meet of the set of points 4376 4377 Not Collective 4378 4379 Input Parameters: 4380 + dm - The DMPlex object 4381 . numPoints - The number of input points for the meet 4382 - points - The input points 4383 4384 Output Parameters: 4385 + numCoveredPoints - The number of points in the meet 4386 - coveredPoints - The points in the meet 4387 4388 Level: intermediate 4389 4390 Note: Currently, this is restricted to a single level meet 4391 4392 Fortran Notes: 4393 Since it returns an array, this routine is only available in Fortran 90, and you must 4394 include petsc.h90 in your code. 4395 4396 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4397 4398 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4399 @*/ 4400 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4401 { 4402 DM_Plex *mesh = (DM_Plex*) dm->data; 4403 PetscInt *meet[2]; 4404 PetscInt meetSize, i = 0; 4405 PetscInt dof, off, p, c, m; 4406 PetscInt maxConeSize; 4407 4408 PetscFunctionBegin; 4409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4410 PetscValidIntPointer(points, 3); 4411 PetscValidIntPointer(numCoveringPoints, 4); 4412 PetscValidPointer(coveringPoints, 5); 4413 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4414 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4415 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4416 /* Copy in cone of first point */ 4417 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4418 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4419 for (meetSize = 0; meetSize < dof; ++meetSize) { 4420 meet[i][meetSize] = mesh->cones[off+meetSize]; 4421 } 4422 /* Check each successive cone */ 4423 for (p = 1; p < numPoints; ++p) { 4424 PetscInt newMeetSize = 0; 4425 4426 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4427 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4428 for (c = 0; c < dof; ++c) { 4429 const PetscInt point = mesh->cones[off+c]; 4430 4431 for (m = 0; m < meetSize; ++m) { 4432 if (point == meet[i][m]) { 4433 meet[1-i][newMeetSize++] = point; 4434 break; 4435 } 4436 } 4437 } 4438 meetSize = newMeetSize; 4439 i = 1-i; 4440 } 4441 *numCoveringPoints = meetSize; 4442 *coveringPoints = meet[i]; 4443 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4444 PetscFunctionReturn(0); 4445 } 4446 4447 /*@C 4448 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4449 4450 Not Collective 4451 4452 Input Parameters: 4453 + dm - The DMPlex object 4454 . numPoints - The number of input points for the meet 4455 - points - The input points 4456 4457 Output Parameters: 4458 + numCoveredPoints - The number of points in the meet 4459 - coveredPoints - The points in the meet 4460 4461 Level: intermediate 4462 4463 Fortran Notes: 4464 Since it returns an array, this routine is only available in Fortran 90, and you must 4465 include petsc.h90 in your code. 4466 4467 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4468 4469 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4470 @*/ 4471 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4472 { 4473 PetscFunctionBegin; 4474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4475 if (points) PetscValidIntPointer(points,3); 4476 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4477 PetscValidPointer(coveredPoints,5); 4478 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4479 if (numCoveredPoints) *numCoveredPoints = 0; 4480 PetscFunctionReturn(0); 4481 } 4482 4483 /*@C 4484 DMPlexGetFullMeet - Get an array for the meet of the set of points 4485 4486 Not Collective 4487 4488 Input Parameters: 4489 + dm - The DMPlex object 4490 . numPoints - The number of input points for the meet 4491 - points - The input points 4492 4493 Output Parameters: 4494 + numCoveredPoints - The number of points in the meet 4495 - coveredPoints - The points in the meet 4496 4497 Level: intermediate 4498 4499 Fortran Notes: 4500 Since it returns an array, this routine is only available in Fortran 90, and you must 4501 include petsc.h90 in your code. 4502 4503 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4504 4505 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4506 @*/ 4507 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4508 { 4509 PetscInt *offsets, **closures; 4510 PetscInt *meet[2]; 4511 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4512 PetscInt p, h, c, m, mc; 4513 4514 PetscFunctionBegin; 4515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4516 PetscValidIntPointer(points, 3); 4517 PetscValidIntPointer(numCoveredPoints, 4); 4518 PetscValidPointer(coveredPoints, 5); 4519 4520 PetscCall(DMPlexGetDepth(dm, &height)); 4521 PetscCall(PetscMalloc1(numPoints, &closures)); 4522 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4523 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4524 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4525 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4526 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4527 4528 for (p = 0; p < numPoints; ++p) { 4529 PetscInt closureSize; 4530 4531 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4532 4533 offsets[p*(height+2)+0] = 0; 4534 for (h = 0; h < height+1; ++h) { 4535 PetscInt pStart, pEnd, i; 4536 4537 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4538 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4539 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4540 offsets[p*(height+2)+h+1] = i; 4541 break; 4542 } 4543 } 4544 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4545 } 4546 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); 4547 } 4548 for (h = 0; h < height+1; ++h) { 4549 PetscInt dof; 4550 4551 /* Copy in cone of first point */ 4552 dof = offsets[h+1] - offsets[h]; 4553 for (meetSize = 0; meetSize < dof; ++meetSize) { 4554 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4555 } 4556 /* Check each successive cone */ 4557 for (p = 1; p < numPoints && meetSize; ++p) { 4558 PetscInt newMeetSize = 0; 4559 4560 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4561 for (c = 0; c < dof; ++c) { 4562 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4563 4564 for (m = 0; m < meetSize; ++m) { 4565 if (point == meet[i][m]) { 4566 meet[1-i][newMeetSize++] = point; 4567 break; 4568 } 4569 } 4570 } 4571 meetSize = newMeetSize; 4572 i = 1-i; 4573 } 4574 if (meetSize) break; 4575 } 4576 *numCoveredPoints = meetSize; 4577 *coveredPoints = meet[i]; 4578 for (p = 0; p < numPoints; ++p) { 4579 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4580 } 4581 PetscCall(PetscFree(closures)); 4582 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4583 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4584 PetscFunctionReturn(0); 4585 } 4586 4587 /*@C 4588 DMPlexEqual - Determine if two DMs have the same topology 4589 4590 Not Collective 4591 4592 Input Parameters: 4593 + dmA - A DMPlex object 4594 - dmB - A DMPlex object 4595 4596 Output Parameters: 4597 . equal - PETSC_TRUE if the topologies are identical 4598 4599 Level: intermediate 4600 4601 Notes: 4602 We are not solving graph isomorphism, so we do not permutation. 4603 4604 .seealso: `DMPlexGetCone()` 4605 @*/ 4606 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4607 { 4608 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4609 4610 PetscFunctionBegin; 4611 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4612 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4613 PetscValidBoolPointer(equal, 3); 4614 4615 *equal = PETSC_FALSE; 4616 PetscCall(DMPlexGetDepth(dmA, &depth)); 4617 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4618 if (depth != depthB) PetscFunctionReturn(0); 4619 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4620 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4621 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4622 for (p = pStart; p < pEnd; ++p) { 4623 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4624 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4625 4626 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4627 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4628 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4629 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4630 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4631 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4632 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4633 for (c = 0; c < coneSize; ++c) { 4634 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4635 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4636 } 4637 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4638 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4639 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4640 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4641 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4642 for (s = 0; s < supportSize; ++s) { 4643 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4644 } 4645 } 4646 *equal = PETSC_TRUE; 4647 PetscFunctionReturn(0); 4648 } 4649 4650 /*@C 4651 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4652 4653 Not Collective 4654 4655 Input Parameters: 4656 + dm - The DMPlex 4657 . cellDim - The cell dimension 4658 - numCorners - The number of vertices on a cell 4659 4660 Output Parameters: 4661 . numFaceVertices - The number of vertices on a face 4662 4663 Level: developer 4664 4665 Notes: 4666 Of course this can only work for a restricted set of symmetric shapes 4667 4668 .seealso: `DMPlexGetCone()` 4669 @*/ 4670 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4671 { 4672 MPI_Comm comm; 4673 4674 PetscFunctionBegin; 4675 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4676 PetscValidIntPointer(numFaceVertices,4); 4677 switch (cellDim) { 4678 case 0: 4679 *numFaceVertices = 0; 4680 break; 4681 case 1: 4682 *numFaceVertices = 1; 4683 break; 4684 case 2: 4685 switch (numCorners) { 4686 case 3: /* triangle */ 4687 *numFaceVertices = 2; /* Edge has 2 vertices */ 4688 break; 4689 case 4: /* quadrilateral */ 4690 *numFaceVertices = 2; /* Edge has 2 vertices */ 4691 break; 4692 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4693 *numFaceVertices = 3; /* Edge has 3 vertices */ 4694 break; 4695 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4696 *numFaceVertices = 3; /* Edge has 3 vertices */ 4697 break; 4698 default: 4699 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4700 } 4701 break; 4702 case 3: 4703 switch (numCorners) { 4704 case 4: /* tetradehdron */ 4705 *numFaceVertices = 3; /* Face has 3 vertices */ 4706 break; 4707 case 6: /* tet cohesive cells */ 4708 *numFaceVertices = 4; /* Face has 4 vertices */ 4709 break; 4710 case 8: /* hexahedron */ 4711 *numFaceVertices = 4; /* Face has 4 vertices */ 4712 break; 4713 case 9: /* tet cohesive Lagrange cells */ 4714 *numFaceVertices = 6; /* Face has 6 vertices */ 4715 break; 4716 case 10: /* quadratic tetrahedron */ 4717 *numFaceVertices = 6; /* Face has 6 vertices */ 4718 break; 4719 case 12: /* hex cohesive Lagrange cells */ 4720 *numFaceVertices = 6; /* Face has 6 vertices */ 4721 break; 4722 case 18: /* quadratic tet cohesive Lagrange cells */ 4723 *numFaceVertices = 6; /* Face has 6 vertices */ 4724 break; 4725 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4726 *numFaceVertices = 9; /* Face has 9 vertices */ 4727 break; 4728 default: 4729 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4730 } 4731 break; 4732 default: 4733 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4734 } 4735 PetscFunctionReturn(0); 4736 } 4737 4738 /*@ 4739 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4740 4741 Not Collective 4742 4743 Input Parameter: 4744 . dm - The DMPlex object 4745 4746 Output Parameter: 4747 . depthLabel - The DMLabel recording point depth 4748 4749 Level: developer 4750 4751 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4752 @*/ 4753 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4754 { 4755 PetscFunctionBegin; 4756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4757 PetscValidPointer(depthLabel, 2); 4758 *depthLabel = dm->depthLabel; 4759 PetscFunctionReturn(0); 4760 } 4761 4762 /*@ 4763 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4764 4765 Not Collective 4766 4767 Input Parameter: 4768 . dm - The DMPlex object 4769 4770 Output Parameter: 4771 . depth - The number of strata (breadth first levels) in the DAG 4772 4773 Level: developer 4774 4775 Notes: 4776 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4777 The point depth is described more in detail in DMPlexGetDepthStratum(). 4778 An empty mesh gives -1. 4779 4780 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4781 @*/ 4782 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4783 { 4784 DMLabel label; 4785 PetscInt d = 0; 4786 4787 PetscFunctionBegin; 4788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4789 PetscValidIntPointer(depth, 2); 4790 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4791 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4792 *depth = d-1; 4793 PetscFunctionReturn(0); 4794 } 4795 4796 /*@ 4797 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4798 4799 Not Collective 4800 4801 Input Parameters: 4802 + dm - The DMPlex object 4803 - depth - The requested depth 4804 4805 Output Parameters: 4806 + start - The first point at this depth 4807 - end - One beyond the last point at this depth 4808 4809 Notes: 4810 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4811 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4812 higher dimension, e.g., "edges". 4813 4814 Level: developer 4815 4816 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4817 @*/ 4818 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4819 { 4820 DMLabel label; 4821 PetscInt pStart, pEnd; 4822 4823 PetscFunctionBegin; 4824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4825 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4826 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4827 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4828 if (pStart == pEnd) PetscFunctionReturn(0); 4829 if (depth < 0) { 4830 if (start) *start = pStart; 4831 if (end) *end = pEnd; 4832 PetscFunctionReturn(0); 4833 } 4834 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4835 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4836 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4837 PetscFunctionReturn(0); 4838 } 4839 4840 /*@ 4841 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4842 4843 Not Collective 4844 4845 Input Parameters: 4846 + dm - The DMPlex object 4847 - height - The requested height 4848 4849 Output Parameters: 4850 + start - The first point at this height 4851 - end - One beyond the last point at this height 4852 4853 Notes: 4854 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4855 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4856 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4857 4858 Level: developer 4859 4860 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4861 @*/ 4862 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4863 { 4864 DMLabel label; 4865 PetscInt depth, pStart, pEnd; 4866 4867 PetscFunctionBegin; 4868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4869 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4870 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4871 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4872 if (pStart == pEnd) PetscFunctionReturn(0); 4873 if (height < 0) { 4874 if (start) *start = pStart; 4875 if (end) *end = pEnd; 4876 PetscFunctionReturn(0); 4877 } 4878 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4879 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4880 PetscCall(DMLabelGetNumValues(label, &depth)); 4881 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4882 PetscFunctionReturn(0); 4883 } 4884 4885 /*@ 4886 DMPlexGetPointDepth - Get the depth of a given point 4887 4888 Not Collective 4889 4890 Input Parameters: 4891 + dm - The DMPlex object 4892 - point - The point 4893 4894 Output Parameter: 4895 . depth - The depth of the point 4896 4897 Level: intermediate 4898 4899 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4900 @*/ 4901 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4902 { 4903 PetscFunctionBegin; 4904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4905 PetscValidIntPointer(depth, 3); 4906 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4907 PetscFunctionReturn(0); 4908 } 4909 4910 /*@ 4911 DMPlexGetPointHeight - Get the height of a given point 4912 4913 Not Collective 4914 4915 Input Parameters: 4916 + dm - The DMPlex object 4917 - point - The point 4918 4919 Output Parameter: 4920 . height - The height of the point 4921 4922 Level: intermediate 4923 4924 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4925 @*/ 4926 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4927 { 4928 PetscInt n, pDepth; 4929 4930 PetscFunctionBegin; 4931 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4932 PetscValidIntPointer(height, 3); 4933 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4934 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4935 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4936 PetscFunctionReturn(0); 4937 } 4938 4939 /*@ 4940 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4941 4942 Not Collective 4943 4944 Input Parameter: 4945 . dm - The DMPlex object 4946 4947 Output Parameter: 4948 . celltypeLabel - The DMLabel recording cell polytope type 4949 4950 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4951 DMCreateLabel(dm, "celltype") beforehand. 4952 4953 Level: developer 4954 4955 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4956 @*/ 4957 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4958 { 4959 PetscFunctionBegin; 4960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4961 PetscValidPointer(celltypeLabel, 2); 4962 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4963 *celltypeLabel = dm->celltypeLabel; 4964 PetscFunctionReturn(0); 4965 } 4966 4967 /*@ 4968 DMPlexGetCellType - Get the polytope type of a given cell 4969 4970 Not Collective 4971 4972 Input Parameters: 4973 + dm - The DMPlex object 4974 - cell - The cell 4975 4976 Output Parameter: 4977 . celltype - The polytope type of the cell 4978 4979 Level: intermediate 4980 4981 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4982 @*/ 4983 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4984 { 4985 DMLabel label; 4986 PetscInt ct; 4987 4988 PetscFunctionBegin; 4989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4990 PetscValidPointer(celltype, 3); 4991 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4992 PetscCall(DMLabelGetValue(label, cell, &ct)); 4993 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4994 *celltype = (DMPolytopeType) ct; 4995 PetscFunctionReturn(0); 4996 } 4997 4998 /*@ 4999 DMPlexSetCellType - Set the polytope type of a given cell 5000 5001 Not Collective 5002 5003 Input Parameters: 5004 + dm - The DMPlex object 5005 . cell - The cell 5006 - celltype - The polytope type of the cell 5007 5008 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5009 is executed. This function will override the computed type. However, if automatic classification will not succeed 5010 and a user wants to manually specify all types, the classification must be disabled by calling 5011 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5012 5013 Level: advanced 5014 5015 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5016 @*/ 5017 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5018 { 5019 DMLabel label; 5020 5021 PetscFunctionBegin; 5022 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5023 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5024 PetscCall(DMLabelSetValue(label, cell, celltype)); 5025 PetscFunctionReturn(0); 5026 } 5027 5028 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5029 { 5030 PetscSection section, s; 5031 Mat m; 5032 PetscInt maxHeight; 5033 5034 PetscFunctionBegin; 5035 PetscCall(DMClone(dm, cdm)); 5036 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5037 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5038 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5039 PetscCall(DMSetLocalSection(*cdm, section)); 5040 PetscCall(PetscSectionDestroy(§ion)); 5041 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5042 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5043 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5044 PetscCall(PetscSectionDestroy(&s)); 5045 PetscCall(MatDestroy(&m)); 5046 5047 PetscCall(DMSetNumFields(*cdm, 1)); 5048 PetscCall(DMCreateDS(*cdm)); 5049 PetscFunctionReturn(0); 5050 } 5051 5052 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5053 { 5054 Vec coordsLocal, cellCoordsLocal; 5055 DM coordsDM, cellCoordsDM; 5056 5057 PetscFunctionBegin; 5058 *field = NULL; 5059 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5060 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5061 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5062 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5063 if (coordsLocal && coordsDM) { 5064 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5065 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5066 } 5067 PetscFunctionReturn(0); 5068 } 5069 5070 /*@C 5071 DMPlexGetConeSection - Return a section which describes the layout of cone data 5072 5073 Not Collective 5074 5075 Input Parameters: 5076 . dm - The DMPlex object 5077 5078 Output Parameter: 5079 . section - The PetscSection object 5080 5081 Level: developer 5082 5083 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5084 @*/ 5085 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5086 { 5087 DM_Plex *mesh = (DM_Plex*) dm->data; 5088 5089 PetscFunctionBegin; 5090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5091 if (section) *section = mesh->coneSection; 5092 PetscFunctionReturn(0); 5093 } 5094 5095 /*@C 5096 DMPlexGetSupportSection - Return a section which describes the layout of support data 5097 5098 Not Collective 5099 5100 Input Parameters: 5101 . dm - The DMPlex object 5102 5103 Output Parameter: 5104 . section - The PetscSection object 5105 5106 Level: developer 5107 5108 .seealso: `DMPlexGetConeSection()` 5109 @*/ 5110 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5111 { 5112 DM_Plex *mesh = (DM_Plex*) dm->data; 5113 5114 PetscFunctionBegin; 5115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5116 if (section) *section = mesh->supportSection; 5117 PetscFunctionReturn(0); 5118 } 5119 5120 /*@C 5121 DMPlexGetCones - Return cone data 5122 5123 Not Collective 5124 5125 Input Parameters: 5126 . dm - The DMPlex object 5127 5128 Output Parameter: 5129 . cones - The cone for each point 5130 5131 Level: developer 5132 5133 .seealso: `DMPlexGetConeSection()` 5134 @*/ 5135 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5136 { 5137 DM_Plex *mesh = (DM_Plex*) dm->data; 5138 5139 PetscFunctionBegin; 5140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5141 if (cones) *cones = mesh->cones; 5142 PetscFunctionReturn(0); 5143 } 5144 5145 /*@C 5146 DMPlexGetConeOrientations - Return cone orientation data 5147 5148 Not Collective 5149 5150 Input Parameters: 5151 . dm - The DMPlex object 5152 5153 Output Parameter: 5154 . coneOrientations - The array of cone orientations for all points 5155 5156 Level: developer 5157 5158 Notes: 5159 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5160 5161 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5162 5163 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5164 @*/ 5165 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5166 { 5167 DM_Plex *mesh = (DM_Plex*) dm->data; 5168 5169 PetscFunctionBegin; 5170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5171 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5172 PetscFunctionReturn(0); 5173 } 5174 5175 /******************************** FEM Support **********************************/ 5176 5177 /* 5178 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5179 representing a line in the section. 5180 */ 5181 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5182 { 5183 PetscFunctionBeginHot; 5184 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5185 if (line < 0) { 5186 *k = 0; 5187 *Nc = 0; 5188 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5189 *k = 1; 5190 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5191 /* An order k SEM disc has k-1 dofs on an edge */ 5192 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5193 *k = *k / *Nc + 1; 5194 } 5195 PetscFunctionReturn(0); 5196 } 5197 5198 /*@ 5199 5200 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5201 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5202 section provided (or the section of the DM). 5203 5204 Input Parameters: 5205 + dm - The DM 5206 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5207 - section - The PetscSection to reorder, or NULL for the default section 5208 5209 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5210 degree of the basis. 5211 5212 Example: 5213 A typical interpolated single-quad mesh might order points as 5214 .vb 5215 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5216 5217 v4 -- e6 -- v3 5218 | | 5219 e7 c0 e8 5220 | | 5221 v1 -- e5 -- v2 5222 .ve 5223 5224 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5225 dofs in the order of points, e.g., 5226 .vb 5227 c0 -> [0,1,2,3] 5228 v1 -> [4] 5229 ... 5230 e5 -> [8, 9] 5231 .ve 5232 5233 which corresponds to the dofs 5234 .vb 5235 6 10 11 7 5236 13 2 3 15 5237 12 0 1 14 5238 4 8 9 5 5239 .ve 5240 5241 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5242 .vb 5243 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5244 .ve 5245 5246 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5247 .vb 5248 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5249 .ve 5250 5251 Level: developer 5252 5253 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5254 @*/ 5255 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5256 { 5257 DMLabel label; 5258 PetscInt dim, depth = -1, eStart = -1, Nf; 5259 PetscBool vertexchart; 5260 5261 PetscFunctionBegin; 5262 PetscCall(DMGetDimension(dm, &dim)); 5263 if (dim < 1) PetscFunctionReturn(0); 5264 if (point < 0) { 5265 PetscInt sStart,sEnd; 5266 5267 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5268 point = sEnd-sStart ? sStart : point; 5269 } 5270 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5271 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5272 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5273 if (depth == 1) {eStart = point;} 5274 else if (depth == dim) { 5275 const PetscInt *cone; 5276 5277 PetscCall(DMPlexGetCone(dm, point, &cone)); 5278 if (dim == 2) eStart = cone[0]; 5279 else if (dim == 3) { 5280 const PetscInt *cone2; 5281 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5282 eStart = cone2[0]; 5283 } 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); 5284 } 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); 5285 { /* Determine whether the chart covers all points or just vertices. */ 5286 PetscInt pStart,pEnd,cStart,cEnd; 5287 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5288 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5289 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5290 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5291 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5292 } 5293 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5294 for (PetscInt d=1; d<=dim; d++) { 5295 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5296 PetscInt *perm; 5297 5298 for (f = 0; f < Nf; ++f) { 5299 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5300 size += PetscPowInt(k+1, d)*Nc; 5301 } 5302 PetscCall(PetscMalloc1(size, &perm)); 5303 for (f = 0; f < Nf; ++f) { 5304 switch (d) { 5305 case 1: 5306 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5307 /* 5308 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5309 We want [ vtx0; edge of length k-1; vtx1 ] 5310 */ 5311 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5312 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5313 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5314 foffset = offset; 5315 break; 5316 case 2: 5317 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5318 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5319 /* The SEM order is 5320 5321 v_lb, {e_b}, v_rb, 5322 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5323 v_lt, reverse {e_t}, v_rt 5324 */ 5325 { 5326 const PetscInt of = 0; 5327 const PetscInt oeb = of + PetscSqr(k-1); 5328 const PetscInt oer = oeb + (k-1); 5329 const PetscInt oet = oer + (k-1); 5330 const PetscInt oel = oet + (k-1); 5331 const PetscInt ovlb = oel + (k-1); 5332 const PetscInt ovrb = ovlb + 1; 5333 const PetscInt ovrt = ovrb + 1; 5334 const PetscInt ovlt = ovrt + 1; 5335 PetscInt o; 5336 5337 /* bottom */ 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5339 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5341 /* middle */ 5342 for (i = 0; i < k-1; ++i) { 5343 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5344 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; 5345 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5346 } 5347 /* top */ 5348 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5349 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5350 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5351 foffset = offset; 5352 } 5353 break; 5354 case 3: 5355 /* The original hex closure is 5356 5357 {c, 5358 f_b, f_t, f_f, f_b, f_r, f_l, 5359 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5360 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5361 */ 5362 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5363 /* The SEM order is 5364 Bottom Slice 5365 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5366 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5367 v_blb, {e_bb}, v_brb, 5368 5369 Middle Slice (j) 5370 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5371 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5372 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5373 5374 Top Slice 5375 v_tlf, {e_tf}, v_trf, 5376 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5377 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5378 */ 5379 { 5380 const PetscInt oc = 0; 5381 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5382 const PetscInt oft = ofb + PetscSqr(k-1); 5383 const PetscInt off = oft + PetscSqr(k-1); 5384 const PetscInt ofk = off + PetscSqr(k-1); 5385 const PetscInt ofr = ofk + PetscSqr(k-1); 5386 const PetscInt ofl = ofr + PetscSqr(k-1); 5387 const PetscInt oebl = ofl + PetscSqr(k-1); 5388 const PetscInt oebb = oebl + (k-1); 5389 const PetscInt oebr = oebb + (k-1); 5390 const PetscInt oebf = oebr + (k-1); 5391 const PetscInt oetf = oebf + (k-1); 5392 const PetscInt oetr = oetf + (k-1); 5393 const PetscInt oetb = oetr + (k-1); 5394 const PetscInt oetl = oetb + (k-1); 5395 const PetscInt oerf = oetl + (k-1); 5396 const PetscInt oelf = oerf + (k-1); 5397 const PetscInt oelb = oelf + (k-1); 5398 const PetscInt oerb = oelb + (k-1); 5399 const PetscInt ovblf = oerb + (k-1); 5400 const PetscInt ovblb = ovblf + 1; 5401 const PetscInt ovbrb = ovblb + 1; 5402 const PetscInt ovbrf = ovbrb + 1; 5403 const PetscInt ovtlf = ovbrf + 1; 5404 const PetscInt ovtrf = ovtlf + 1; 5405 const PetscInt ovtrb = ovtrf + 1; 5406 const PetscInt ovtlb = ovtrb + 1; 5407 PetscInt o, n; 5408 5409 /* Bottom Slice */ 5410 /* bottom */ 5411 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5412 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5414 /* middle */ 5415 for (i = 0; i < k-1; ++i) { 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5417 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;} 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5419 } 5420 /* top */ 5421 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5422 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5424 5425 /* Middle Slice */ 5426 for (j = 0; j < k-1; ++j) { 5427 /* bottom */ 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5429 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; 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5431 /* middle */ 5432 for (i = 0; i < k-1; ++i) { 5433 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5434 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; 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5436 } 5437 /* top */ 5438 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5439 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; 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5441 } 5442 5443 /* Top Slice */ 5444 /* bottom */ 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5446 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5448 /* middle */ 5449 for (i = 0; i < k-1; ++i) { 5450 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5451 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5452 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5453 } 5454 /* top */ 5455 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5456 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5457 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5458 5459 foffset = offset; 5460 } 5461 break; 5462 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5463 } 5464 } 5465 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5466 /* Check permutation */ 5467 { 5468 PetscInt *check; 5469 5470 PetscCall(PetscMalloc1(size, &check)); 5471 for (i = 0; i < size; ++i) { 5472 check[i] = -1; 5473 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5474 } 5475 for (i = 0; i < size; ++i) check[perm[i]] = i; 5476 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5477 PetscCall(PetscFree(check)); 5478 } 5479 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5480 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5481 PetscInt *loc_perm; 5482 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5483 for (PetscInt i=0; i<size; i++) { 5484 loc_perm[i] = perm[i]; 5485 loc_perm[size+i] = size + perm[i]; 5486 } 5487 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5488 } 5489 } 5490 PetscFunctionReturn(0); 5491 } 5492 5493 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5494 { 5495 PetscDS prob; 5496 PetscInt depth, Nf, h; 5497 DMLabel label; 5498 5499 PetscFunctionBeginHot; 5500 PetscCall(DMGetDS(dm, &prob)); 5501 Nf = prob->Nf; 5502 label = dm->depthLabel; 5503 *dspace = NULL; 5504 if (field < Nf) { 5505 PetscObject disc = prob->disc[field]; 5506 5507 if (disc->classid == PETSCFE_CLASSID) { 5508 PetscDualSpace dsp; 5509 5510 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5511 PetscCall(DMLabelGetNumValues(label,&depth)); 5512 PetscCall(DMLabelGetValue(label,point,&h)); 5513 h = depth - 1 - h; 5514 if (h) { 5515 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5516 } else { 5517 *dspace = dsp; 5518 } 5519 } 5520 } 5521 PetscFunctionReturn(0); 5522 } 5523 5524 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5525 { 5526 PetscScalar *array; 5527 const PetscScalar *vArray; 5528 const PetscInt *cone, *coneO; 5529 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5530 5531 PetscFunctionBeginHot; 5532 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5533 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5534 PetscCall(DMPlexGetCone(dm, point, &cone)); 5535 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5536 if (!values || !*values) { 5537 if ((point >= pStart) && (point < pEnd)) { 5538 PetscInt dof; 5539 5540 PetscCall(PetscSectionGetDof(section, point, &dof)); 5541 size += dof; 5542 } 5543 for (p = 0; p < numPoints; ++p) { 5544 const PetscInt cp = cone[p]; 5545 PetscInt dof; 5546 5547 if ((cp < pStart) || (cp >= pEnd)) continue; 5548 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5549 size += dof; 5550 } 5551 if (!values) { 5552 if (csize) *csize = size; 5553 PetscFunctionReturn(0); 5554 } 5555 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5556 } else { 5557 array = *values; 5558 } 5559 size = 0; 5560 PetscCall(VecGetArrayRead(v, &vArray)); 5561 if ((point >= pStart) && (point < pEnd)) { 5562 PetscInt dof, off, d; 5563 const PetscScalar *varr; 5564 5565 PetscCall(PetscSectionGetDof(section, point, &dof)); 5566 PetscCall(PetscSectionGetOffset(section, point, &off)); 5567 varr = &vArray[off]; 5568 for (d = 0; d < dof; ++d, ++offset) { 5569 array[offset] = varr[d]; 5570 } 5571 size += dof; 5572 } 5573 for (p = 0; p < numPoints; ++p) { 5574 const PetscInt cp = cone[p]; 5575 PetscInt o = coneO[p]; 5576 PetscInt dof, off, d; 5577 const PetscScalar *varr; 5578 5579 if ((cp < pStart) || (cp >= pEnd)) continue; 5580 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5581 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5582 varr = &vArray[off]; 5583 if (o >= 0) { 5584 for (d = 0; d < dof; ++d, ++offset) { 5585 array[offset] = varr[d]; 5586 } 5587 } else { 5588 for (d = dof-1; d >= 0; --d, ++offset) { 5589 array[offset] = varr[d]; 5590 } 5591 } 5592 size += dof; 5593 } 5594 PetscCall(VecRestoreArrayRead(v, &vArray)); 5595 if (!*values) { 5596 if (csize) *csize = size; 5597 *values = array; 5598 } else { 5599 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5600 *csize = size; 5601 } 5602 PetscFunctionReturn(0); 5603 } 5604 5605 /* Compress out points not in the section */ 5606 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5607 { 5608 const PetscInt np = *numPoints; 5609 PetscInt pStart, pEnd, p, q; 5610 5611 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5612 for (p = 0, q = 0; p < np; ++p) { 5613 const PetscInt r = points[p*2]; 5614 if ((r >= pStart) && (r < pEnd)) { 5615 points[q*2] = r; 5616 points[q*2+1] = points[p*2+1]; 5617 ++q; 5618 } 5619 } 5620 *numPoints = q; 5621 return 0; 5622 } 5623 5624 /* Compressed closure does not apply closure permutation */ 5625 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5626 { 5627 const PetscInt *cla = NULL; 5628 PetscInt np, *pts = NULL; 5629 5630 PetscFunctionBeginHot; 5631 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5632 if (*clPoints) { 5633 PetscInt dof, off; 5634 5635 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5636 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5637 PetscCall(ISGetIndices(*clPoints, &cla)); 5638 np = dof/2; 5639 pts = (PetscInt *) &cla[off]; 5640 } else { 5641 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5642 PetscCall(CompressPoints_Private(section, &np, pts)); 5643 } 5644 *numPoints = np; 5645 *points = pts; 5646 *clp = cla; 5647 PetscFunctionReturn(0); 5648 } 5649 5650 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5651 { 5652 PetscFunctionBeginHot; 5653 if (!*clPoints) { 5654 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5655 } else { 5656 PetscCall(ISRestoreIndices(*clPoints, clp)); 5657 } 5658 *numPoints = 0; 5659 *points = NULL; 5660 *clSec = NULL; 5661 *clPoints = NULL; 5662 *clp = NULL; 5663 PetscFunctionReturn(0); 5664 } 5665 5666 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5667 { 5668 PetscInt offset = 0, p; 5669 const PetscInt **perms = NULL; 5670 const PetscScalar **flips = NULL; 5671 5672 PetscFunctionBeginHot; 5673 *size = 0; 5674 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5675 for (p = 0; p < numPoints; p++) { 5676 const PetscInt point = points[2*p]; 5677 const PetscInt *perm = perms ? perms[p] : NULL; 5678 const PetscScalar *flip = flips ? flips[p] : NULL; 5679 PetscInt dof, off, d; 5680 const PetscScalar *varr; 5681 5682 PetscCall(PetscSectionGetDof(section, point, &dof)); 5683 PetscCall(PetscSectionGetOffset(section, point, &off)); 5684 varr = &vArray[off]; 5685 if (clperm) { 5686 if (perm) { 5687 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5688 } else { 5689 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5690 } 5691 if (flip) { 5692 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5693 } 5694 } else { 5695 if (perm) { 5696 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5697 } else { 5698 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5699 } 5700 if (flip) { 5701 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5702 } 5703 } 5704 offset += dof; 5705 } 5706 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5707 *size = offset; 5708 PetscFunctionReturn(0); 5709 } 5710 5711 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[]) 5712 { 5713 PetscInt offset = 0, f; 5714 5715 PetscFunctionBeginHot; 5716 *size = 0; 5717 for (f = 0; f < numFields; ++f) { 5718 PetscInt p; 5719 const PetscInt **perms = NULL; 5720 const PetscScalar **flips = NULL; 5721 5722 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5723 for (p = 0; p < numPoints; p++) { 5724 const PetscInt point = points[2*p]; 5725 PetscInt fdof, foff, b; 5726 const PetscScalar *varr; 5727 const PetscInt *perm = perms ? perms[p] : NULL; 5728 const PetscScalar *flip = flips ? flips[p] : NULL; 5729 5730 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5731 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5732 varr = &vArray[foff]; 5733 if (clperm) { 5734 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5735 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5736 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5737 } else { 5738 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5739 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5740 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5741 } 5742 offset += fdof; 5743 } 5744 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5745 } 5746 *size = offset; 5747 PetscFunctionReturn(0); 5748 } 5749 5750 /*@C 5751 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5752 5753 Not collective 5754 5755 Input Parameters: 5756 + dm - The DM 5757 . section - The section describing the layout in v, or NULL to use the default section 5758 . v - The local vector 5759 - point - The point in the DM 5760 5761 Input/Output Parameters: 5762 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5763 - values - An array to use for the values, or NULL to have it allocated automatically; 5764 if the user provided NULL, it is a borrowed array and should not be freed 5765 5766 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5767 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5768 $ assembly function, and a user may already have allocated storage for this operation. 5769 $ 5770 $ A typical use could be 5771 $ 5772 $ values = NULL; 5773 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5774 $ for (cl = 0; cl < clSize; ++cl) { 5775 $ <Compute on closure> 5776 $ } 5777 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5778 $ 5779 $ or 5780 $ 5781 $ PetscMalloc1(clMaxSize, &values); 5782 $ for (p = pStart; p < pEnd; ++p) { 5783 $ clSize = clMaxSize; 5784 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5785 $ for (cl = 0; cl < clSize; ++cl) { 5786 $ <Compute on closure> 5787 $ } 5788 $ } 5789 $ PetscFree(values); 5790 5791 Fortran Notes: 5792 Since it returns an array, this routine is only available in Fortran 90, and you must 5793 include petsc.h90 in your code. 5794 5795 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5796 5797 Level: intermediate 5798 5799 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5800 @*/ 5801 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5802 { 5803 PetscSection clSection; 5804 IS clPoints; 5805 PetscInt *points = NULL; 5806 const PetscInt *clp, *perm; 5807 PetscInt depth, numFields, numPoints, asize; 5808 5809 PetscFunctionBeginHot; 5810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5811 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5812 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5813 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5814 PetscCall(DMPlexGetDepth(dm, &depth)); 5815 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5816 if (depth == 1 && numFields < 2) { 5817 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5818 PetscFunctionReturn(0); 5819 } 5820 /* Get points */ 5821 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5822 /* Get sizes */ 5823 asize = 0; 5824 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5825 PetscInt dof; 5826 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5827 asize += dof; 5828 } 5829 if (values) { 5830 const PetscScalar *vArray; 5831 PetscInt size; 5832 5833 if (*values) { 5834 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); 5835 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5836 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5837 PetscCall(VecGetArrayRead(v, &vArray)); 5838 /* Get values */ 5839 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5840 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5841 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5842 /* Cleanup array */ 5843 PetscCall(VecRestoreArrayRead(v, &vArray)); 5844 } 5845 if (csize) *csize = asize; 5846 /* Cleanup points */ 5847 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5848 PetscFunctionReturn(0); 5849 } 5850 5851 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5852 { 5853 DMLabel depthLabel; 5854 PetscSection clSection; 5855 IS clPoints; 5856 PetscScalar *array; 5857 const PetscScalar *vArray; 5858 PetscInt *points = NULL; 5859 const PetscInt *clp, *perm = NULL; 5860 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5861 5862 PetscFunctionBeginHot; 5863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5864 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5865 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5866 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5867 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5868 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5869 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5870 if (mdepth == 1 && numFields < 2) { 5871 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5872 PetscFunctionReturn(0); 5873 } 5874 /* Get points */ 5875 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5876 for (clsize=0,p=0; p<Np; p++) { 5877 PetscInt dof; 5878 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5879 clsize += dof; 5880 } 5881 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5882 /* Filter points */ 5883 for (p = 0; p < numPoints*2; p += 2) { 5884 PetscInt dep; 5885 5886 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5887 if (dep != depth) continue; 5888 points[Np*2+0] = points[p]; 5889 points[Np*2+1] = points[p+1]; 5890 ++Np; 5891 } 5892 /* Get array */ 5893 if (!values || !*values) { 5894 PetscInt asize = 0, dof; 5895 5896 for (p = 0; p < Np*2; p += 2) { 5897 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5898 asize += dof; 5899 } 5900 if (!values) { 5901 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5902 if (csize) *csize = asize; 5903 PetscFunctionReturn(0); 5904 } 5905 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5906 } else { 5907 array = *values; 5908 } 5909 PetscCall(VecGetArrayRead(v, &vArray)); 5910 /* Get values */ 5911 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5912 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5913 /* Cleanup points */ 5914 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5915 /* Cleanup array */ 5916 PetscCall(VecRestoreArrayRead(v, &vArray)); 5917 if (!*values) { 5918 if (csize) *csize = size; 5919 *values = array; 5920 } else { 5921 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5922 *csize = size; 5923 } 5924 PetscFunctionReturn(0); 5925 } 5926 5927 /*@C 5928 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5929 5930 Not collective 5931 5932 Input Parameters: 5933 + dm - The DM 5934 . section - The section describing the layout in v, or NULL to use the default section 5935 . v - The local vector 5936 . point - The point in the DM 5937 . csize - The number of values in the closure, or NULL 5938 - values - The array of values, which is a borrowed array and should not be freed 5939 5940 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5941 5942 Fortran Notes: 5943 Since it returns an array, this routine is only available in Fortran 90, and you must 5944 include petsc.h90 in your code. 5945 5946 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5947 5948 Level: intermediate 5949 5950 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5951 @*/ 5952 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5953 { 5954 PetscInt size = 0; 5955 5956 PetscFunctionBegin; 5957 /* Should work without recalculating size */ 5958 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5959 *values = NULL; 5960 PetscFunctionReturn(0); 5961 } 5962 5963 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5964 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5965 5966 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[]) 5967 { 5968 PetscInt cdof; /* The number of constraints on this point */ 5969 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5970 PetscScalar *a; 5971 PetscInt off, cind = 0, k; 5972 5973 PetscFunctionBegin; 5974 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5975 PetscCall(PetscSectionGetOffset(section, point, &off)); 5976 a = &array[off]; 5977 if (!cdof || setBC) { 5978 if (clperm) { 5979 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5980 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5981 } else { 5982 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5983 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5984 } 5985 } else { 5986 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5987 if (clperm) { 5988 if (perm) {for (k = 0; k < dof; ++k) { 5989 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5990 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5991 } 5992 } else { 5993 for (k = 0; k < dof; ++k) { 5994 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5995 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5996 } 5997 } 5998 } else { 5999 if (perm) { 6000 for (k = 0; k < dof; ++k) { 6001 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6002 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6003 } 6004 } else { 6005 for (k = 0; k < dof; ++k) { 6006 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6007 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6008 } 6009 } 6010 } 6011 } 6012 PetscFunctionReturn(0); 6013 } 6014 6015 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[]) 6016 { 6017 PetscInt cdof; /* The number of constraints on this point */ 6018 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6019 PetscScalar *a; 6020 PetscInt off, cind = 0, k; 6021 6022 PetscFunctionBegin; 6023 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6024 PetscCall(PetscSectionGetOffset(section, point, &off)); 6025 a = &array[off]; 6026 if (cdof) { 6027 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6028 if (clperm) { 6029 if (perm) { 6030 for (k = 0; k < dof; ++k) { 6031 if ((cind < cdof) && (k == cdofs[cind])) { 6032 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6033 cind++; 6034 } 6035 } 6036 } else { 6037 for (k = 0; k < dof; ++k) { 6038 if ((cind < cdof) && (k == cdofs[cind])) { 6039 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6040 cind++; 6041 } 6042 } 6043 } 6044 } else { 6045 if (perm) { 6046 for (k = 0; k < dof; ++k) { 6047 if ((cind < cdof) && (k == cdofs[cind])) { 6048 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6049 cind++; 6050 } 6051 } 6052 } else { 6053 for (k = 0; k < dof; ++k) { 6054 if ((cind < cdof) && (k == cdofs[cind])) { 6055 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6056 cind++; 6057 } 6058 } 6059 } 6060 } 6061 } 6062 PetscFunctionReturn(0); 6063 } 6064 6065 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[]) 6066 { 6067 PetscScalar *a; 6068 PetscInt fdof, foff, fcdof, foffset = *offset; 6069 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6070 PetscInt cind = 0, b; 6071 6072 PetscFunctionBegin; 6073 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6074 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6075 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6076 a = &array[foff]; 6077 if (!fcdof || setBC) { 6078 if (clperm) { 6079 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6080 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6081 } else { 6082 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6083 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6084 } 6085 } else { 6086 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6087 if (clperm) { 6088 if (perm) { 6089 for (b = 0; b < fdof; b++) { 6090 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6091 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6092 } 6093 } else { 6094 for (b = 0; b < fdof; b++) { 6095 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6096 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6097 } 6098 } 6099 } else { 6100 if (perm) { 6101 for (b = 0; b < fdof; b++) { 6102 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6103 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6104 } 6105 } else { 6106 for (b = 0; b < fdof; b++) { 6107 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6108 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6109 } 6110 } 6111 } 6112 } 6113 *offset += fdof; 6114 PetscFunctionReturn(0); 6115 } 6116 6117 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[]) 6118 { 6119 PetscScalar *a; 6120 PetscInt fdof, foff, fcdof, foffset = *offset; 6121 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6122 PetscInt Nc, cind = 0, ncind = 0, b; 6123 PetscBool ncSet, fcSet; 6124 6125 PetscFunctionBegin; 6126 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6127 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6128 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6129 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6130 a = &array[foff]; 6131 if (fcdof) { 6132 /* We just override fcdof and fcdofs with Ncc and comps */ 6133 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6134 if (clperm) { 6135 if (perm) { 6136 if (comps) { 6137 for (b = 0; b < fdof; b++) { 6138 ncSet = fcSet = PETSC_FALSE; 6139 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6140 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6141 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6142 } 6143 } else { 6144 for (b = 0; b < fdof; b++) { 6145 if ((cind < fcdof) && (b == fcdofs[cind])) { 6146 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6147 ++cind; 6148 } 6149 } 6150 } 6151 } else { 6152 if (comps) { 6153 for (b = 0; b < fdof; b++) { 6154 ncSet = fcSet = PETSC_FALSE; 6155 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6156 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6157 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6158 } 6159 } else { 6160 for (b = 0; b < fdof; b++) { 6161 if ((cind < fcdof) && (b == fcdofs[cind])) { 6162 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6163 ++cind; 6164 } 6165 } 6166 } 6167 } 6168 } else { 6169 if (perm) { 6170 if (comps) { 6171 for (b = 0; b < fdof; b++) { 6172 ncSet = fcSet = PETSC_FALSE; 6173 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6174 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6175 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6176 } 6177 } else { 6178 for (b = 0; b < fdof; b++) { 6179 if ((cind < fcdof) && (b == fcdofs[cind])) { 6180 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6181 ++cind; 6182 } 6183 } 6184 } 6185 } else { 6186 if (comps) { 6187 for (b = 0; b < fdof; b++) { 6188 ncSet = fcSet = PETSC_FALSE; 6189 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6190 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6191 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6192 } 6193 } else { 6194 for (b = 0; b < fdof; b++) { 6195 if ((cind < fcdof) && (b == fcdofs[cind])) { 6196 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6197 ++cind; 6198 } 6199 } 6200 } 6201 } 6202 } 6203 } 6204 *offset += fdof; 6205 PetscFunctionReturn(0); 6206 } 6207 6208 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6209 { 6210 PetscScalar *array; 6211 const PetscInt *cone, *coneO; 6212 PetscInt pStart, pEnd, p, numPoints, off, dof; 6213 6214 PetscFunctionBeginHot; 6215 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6216 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6217 PetscCall(DMPlexGetCone(dm, point, &cone)); 6218 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6219 PetscCall(VecGetArray(v, &array)); 6220 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6221 const PetscInt cp = !p ? point : cone[p-1]; 6222 const PetscInt o = !p ? 0 : coneO[p-1]; 6223 6224 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6225 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6226 /* ADD_VALUES */ 6227 { 6228 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6229 PetscScalar *a; 6230 PetscInt cdof, coff, cind = 0, k; 6231 6232 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6233 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6234 a = &array[coff]; 6235 if (!cdof) { 6236 if (o >= 0) { 6237 for (k = 0; k < dof; ++k) { 6238 a[k] += values[off+k]; 6239 } 6240 } else { 6241 for (k = 0; k < dof; ++k) { 6242 a[k] += values[off+dof-k-1]; 6243 } 6244 } 6245 } else { 6246 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6247 if (o >= 0) { 6248 for (k = 0; k < dof; ++k) { 6249 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6250 a[k] += values[off+k]; 6251 } 6252 } else { 6253 for (k = 0; k < dof; ++k) { 6254 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6255 a[k] += values[off+dof-k-1]; 6256 } 6257 } 6258 } 6259 } 6260 } 6261 PetscCall(VecRestoreArray(v, &array)); 6262 PetscFunctionReturn(0); 6263 } 6264 6265 /*@C 6266 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6267 6268 Not collective 6269 6270 Input Parameters: 6271 + dm - The DM 6272 . section - The section describing the layout in v, or NULL to use the default section 6273 . v - The local vector 6274 . point - The point in the DM 6275 . values - The array of values 6276 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6277 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6278 6279 Fortran Notes: 6280 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6281 6282 Level: intermediate 6283 6284 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6285 @*/ 6286 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6287 { 6288 PetscSection clSection; 6289 IS clPoints; 6290 PetscScalar *array; 6291 PetscInt *points = NULL; 6292 const PetscInt *clp, *clperm = NULL; 6293 PetscInt depth, numFields, numPoints, p, clsize; 6294 6295 PetscFunctionBeginHot; 6296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6297 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6298 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6299 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6300 PetscCall(DMPlexGetDepth(dm, &depth)); 6301 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6302 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6303 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6304 PetscFunctionReturn(0); 6305 } 6306 /* Get points */ 6307 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6308 for (clsize=0,p=0; p<numPoints; p++) { 6309 PetscInt dof; 6310 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6311 clsize += dof; 6312 } 6313 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6314 /* Get array */ 6315 PetscCall(VecGetArray(v, &array)); 6316 /* Get values */ 6317 if (numFields > 0) { 6318 PetscInt offset = 0, f; 6319 for (f = 0; f < numFields; ++f) { 6320 const PetscInt **perms = NULL; 6321 const PetscScalar **flips = NULL; 6322 6323 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6324 switch (mode) { 6325 case INSERT_VALUES: 6326 for (p = 0; p < numPoints; p++) { 6327 const PetscInt point = points[2*p]; 6328 const PetscInt *perm = perms ? perms[p] : NULL; 6329 const PetscScalar *flip = flips ? flips[p] : NULL; 6330 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6331 } break; 6332 case INSERT_ALL_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_TRUE, clperm, values, &offset, array); 6338 } break; 6339 case INSERT_BC_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 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6345 } break; 6346 case ADD_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 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6352 } break; 6353 case ADD_ALL_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_TRUE, clperm, values, &offset, array); 6359 } break; 6360 case ADD_BC_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 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6366 } break; 6367 default: 6368 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6369 } 6370 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6371 } 6372 } else { 6373 PetscInt dof, off; 6374 const PetscInt **perms = NULL; 6375 const PetscScalar **flips = NULL; 6376 6377 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6378 switch (mode) { 6379 case INSERT_VALUES: 6380 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6381 const PetscInt point = points[2*p]; 6382 const PetscInt *perm = perms ? perms[p] : NULL; 6383 const PetscScalar *flip = flips ? flips[p] : NULL; 6384 PetscCall(PetscSectionGetDof(section, point, &dof)); 6385 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6386 } break; 6387 case INSERT_ALL_VALUES: 6388 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6389 const PetscInt point = points[2*p]; 6390 const PetscInt *perm = perms ? perms[p] : NULL; 6391 const PetscScalar *flip = flips ? flips[p] : NULL; 6392 PetscCall(PetscSectionGetDof(section, point, &dof)); 6393 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6394 } break; 6395 case INSERT_BC_VALUES: 6396 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6397 const PetscInt point = points[2*p]; 6398 const PetscInt *perm = perms ? perms[p] : NULL; 6399 const PetscScalar *flip = flips ? flips[p] : NULL; 6400 PetscCall(PetscSectionGetDof(section, point, &dof)); 6401 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6402 } break; 6403 case ADD_VALUES: 6404 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6405 const PetscInt point = points[2*p]; 6406 const PetscInt *perm = perms ? perms[p] : NULL; 6407 const PetscScalar *flip = flips ? flips[p] : NULL; 6408 PetscCall(PetscSectionGetDof(section, point, &dof)); 6409 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6410 } break; 6411 case ADD_ALL_VALUES: 6412 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6413 const PetscInt point = points[2*p]; 6414 const PetscInt *perm = perms ? perms[p] : NULL; 6415 const PetscScalar *flip = flips ? flips[p] : NULL; 6416 PetscCall(PetscSectionGetDof(section, point, &dof)); 6417 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6418 } break; 6419 case ADD_BC_VALUES: 6420 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6421 const PetscInt point = points[2*p]; 6422 const PetscInt *perm = perms ? perms[p] : NULL; 6423 const PetscScalar *flip = flips ? flips[p] : NULL; 6424 PetscCall(PetscSectionGetDof(section, point, &dof)); 6425 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6426 } break; 6427 default: 6428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6429 } 6430 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6431 } 6432 /* Cleanup points */ 6433 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6434 /* Cleanup array */ 6435 PetscCall(VecRestoreArray(v, &array)); 6436 PetscFunctionReturn(0); 6437 } 6438 6439 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6440 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6441 { 6442 PetscFunctionBegin; 6443 if (label) { 6444 PetscBool contains; 6445 PetscInt fdof; 6446 6447 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6448 if (!contains) { 6449 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6450 *offset += fdof; 6451 PetscFunctionReturn(1); 6452 } 6453 } 6454 PetscFunctionReturn(0); 6455 } 6456 6457 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6458 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) 6459 { 6460 PetscSection clSection; 6461 IS clPoints; 6462 PetscScalar *array; 6463 PetscInt *points = NULL; 6464 const PetscInt *clp; 6465 PetscInt numFields, numPoints, p; 6466 PetscInt offset = 0, f; 6467 6468 PetscFunctionBeginHot; 6469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6470 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6471 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6472 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6473 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6474 /* Get points */ 6475 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6476 /* Get array */ 6477 PetscCall(VecGetArray(v, &array)); 6478 /* Get values */ 6479 for (f = 0; f < numFields; ++f) { 6480 const PetscInt **perms = NULL; 6481 const PetscScalar **flips = NULL; 6482 6483 if (!fieldActive[f]) { 6484 for (p = 0; p < numPoints*2; p += 2) { 6485 PetscInt fdof; 6486 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6487 offset += fdof; 6488 } 6489 continue; 6490 } 6491 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6492 switch (mode) { 6493 case INSERT_VALUES: 6494 for (p = 0; p < numPoints; p++) { 6495 const PetscInt point = points[2*p]; 6496 const PetscInt *perm = perms ? perms[p] : NULL; 6497 const PetscScalar *flip = flips ? flips[p] : NULL; 6498 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6499 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6500 } break; 6501 case INSERT_ALL_VALUES: 6502 for (p = 0; p < numPoints; p++) { 6503 const PetscInt point = points[2*p]; 6504 const PetscInt *perm = perms ? perms[p] : NULL; 6505 const PetscScalar *flip = flips ? flips[p] : NULL; 6506 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6507 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6508 } break; 6509 case INSERT_BC_VALUES: 6510 for (p = 0; p < numPoints; p++) { 6511 const PetscInt point = points[2*p]; 6512 const PetscInt *perm = perms ? perms[p] : NULL; 6513 const PetscScalar *flip = flips ? flips[p] : NULL; 6514 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6515 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6516 } break; 6517 case ADD_VALUES: 6518 for (p = 0; p < numPoints; p++) { 6519 const PetscInt point = points[2*p]; 6520 const PetscInt *perm = perms ? perms[p] : NULL; 6521 const PetscScalar *flip = flips ? flips[p] : NULL; 6522 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6523 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6524 } break; 6525 case ADD_ALL_VALUES: 6526 for (p = 0; p < numPoints; p++) { 6527 const PetscInt point = points[2*p]; 6528 const PetscInt *perm = perms ? perms[p] : NULL; 6529 const PetscScalar *flip = flips ? flips[p] : NULL; 6530 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6531 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6532 } break; 6533 default: 6534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6535 } 6536 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6537 } 6538 /* Cleanup points */ 6539 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6540 /* Cleanup array */ 6541 PetscCall(VecRestoreArray(v, &array)); 6542 PetscFunctionReturn(0); 6543 } 6544 6545 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6546 { 6547 PetscMPIInt rank; 6548 PetscInt i, j; 6549 6550 PetscFunctionBegin; 6551 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6552 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6553 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6554 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6555 numCIndices = numCIndices ? numCIndices : numRIndices; 6556 if (!values) PetscFunctionReturn(0); 6557 for (i = 0; i < numRIndices; i++) { 6558 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6559 for (j = 0; j < numCIndices; j++) { 6560 #if defined(PETSC_USE_COMPLEX) 6561 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6562 #else 6563 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6564 #endif 6565 } 6566 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6567 } 6568 PetscFunctionReturn(0); 6569 } 6570 6571 /* 6572 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6573 6574 Input Parameters: 6575 + section - The section for this data layout 6576 . islocal - Is the section (and thus indices being requested) local or global? 6577 . point - The point contributing dofs with these indices 6578 . off - The global offset of this point 6579 . loff - The local offset of each field 6580 . setBC - The flag determining whether to include indices of boundary values 6581 . perm - A permutation of the dofs on this point, or NULL 6582 - indperm - A permutation of the entire indices array, or NULL 6583 6584 Output Parameter: 6585 . indices - Indices for dofs on this point 6586 6587 Level: developer 6588 6589 Note: The indices could be local or global, depending on the value of 'off'. 6590 */ 6591 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6592 { 6593 PetscInt dof; /* The number of unknowns on this point */ 6594 PetscInt cdof; /* The number of constraints on this point */ 6595 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6596 PetscInt cind = 0, k; 6597 6598 PetscFunctionBegin; 6599 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6600 PetscCall(PetscSectionGetDof(section, point, &dof)); 6601 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6602 if (!cdof || setBC) { 6603 for (k = 0; k < dof; ++k) { 6604 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6605 const PetscInt ind = indperm ? indperm[preind] : preind; 6606 6607 indices[ind] = off + k; 6608 } 6609 } else { 6610 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6611 for (k = 0; k < dof; ++k) { 6612 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6613 const PetscInt ind = indperm ? indperm[preind] : preind; 6614 6615 if ((cind < cdof) && (k == cdofs[cind])) { 6616 /* Insert check for returning constrained indices */ 6617 indices[ind] = -(off+k+1); 6618 ++cind; 6619 } else { 6620 indices[ind] = off + k - (islocal ? 0 : cind); 6621 } 6622 } 6623 } 6624 *loff += dof; 6625 PetscFunctionReturn(0); 6626 } 6627 6628 /* 6629 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6630 6631 Input Parameters: 6632 + section - a section (global or local) 6633 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6634 . point - point within section 6635 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6636 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6637 . setBC - identify constrained (boundary condition) points via involution. 6638 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6639 . permsoff - offset 6640 - indperm - index permutation 6641 6642 Output Parameter: 6643 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6644 . indices - array to hold indices (as defined by section) of each dof associated with point 6645 6646 Notes: 6647 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6648 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6649 in the local vector. 6650 6651 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6652 significant). It is invalid to call with a global section and setBC=true. 6653 6654 Developer Note: 6655 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6656 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6657 offset could be obtained from the section instead of passing it explicitly as we do now. 6658 6659 Example: 6660 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6661 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6662 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6663 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. 6664 6665 Level: developer 6666 */ 6667 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[]) 6668 { 6669 PetscInt numFields, foff, f; 6670 6671 PetscFunctionBegin; 6672 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6673 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6674 for (f = 0, foff = 0; f < numFields; ++f) { 6675 PetscInt fdof, cfdof; 6676 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6677 PetscInt cind = 0, b; 6678 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6679 6680 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6681 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6682 if (!cfdof || setBC) { 6683 for (b = 0; b < fdof; ++b) { 6684 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6685 const PetscInt ind = indperm ? indperm[preind] : preind; 6686 6687 indices[ind] = off+foff+b; 6688 } 6689 } else { 6690 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6691 for (b = 0; b < fdof; ++b) { 6692 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6693 const PetscInt ind = indperm ? indperm[preind] : preind; 6694 6695 if ((cind < cfdof) && (b == fcdofs[cind])) { 6696 indices[ind] = -(off+foff+b+1); 6697 ++cind; 6698 } else { 6699 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6700 } 6701 } 6702 } 6703 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6704 foffs[f] += fdof; 6705 } 6706 PetscFunctionReturn(0); 6707 } 6708 6709 /* 6710 This version believes the globalSection offsets for each field, rather than just the point offset 6711 6712 . foffs - The offset into 'indices' for each field, since it is segregated by field 6713 6714 Notes: 6715 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6716 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6717 */ 6718 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6719 { 6720 PetscInt numFields, foff, f; 6721 6722 PetscFunctionBegin; 6723 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6724 for (f = 0; f < numFields; ++f) { 6725 PetscInt fdof, cfdof; 6726 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6727 PetscInt cind = 0, b; 6728 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6729 6730 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6731 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6732 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6733 if (!cfdof) { 6734 for (b = 0; b < fdof; ++b) { 6735 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6736 const PetscInt ind = indperm ? indperm[preind] : preind; 6737 6738 indices[ind] = foff+b; 6739 } 6740 } else { 6741 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6742 for (b = 0; b < fdof; ++b) { 6743 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6744 const PetscInt ind = indperm ? indperm[preind] : preind; 6745 6746 if ((cind < cfdof) && (b == fcdofs[cind])) { 6747 indices[ind] = -(foff+b+1); 6748 ++cind; 6749 } else { 6750 indices[ind] = foff+b-cind; 6751 } 6752 } 6753 } 6754 foffs[f] += fdof; 6755 } 6756 PetscFunctionReturn(0); 6757 } 6758 6759 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) 6760 { 6761 Mat cMat; 6762 PetscSection aSec, cSec; 6763 IS aIS; 6764 PetscInt aStart = -1, aEnd = -1; 6765 const PetscInt *anchors; 6766 PetscInt numFields, f, p, q, newP = 0; 6767 PetscInt newNumPoints = 0, newNumIndices = 0; 6768 PetscInt *newPoints, *indices, *newIndices; 6769 PetscInt maxAnchor, maxDof; 6770 PetscInt newOffsets[32]; 6771 PetscInt *pointMatOffsets[32]; 6772 PetscInt *newPointOffsets[32]; 6773 PetscScalar *pointMat[32]; 6774 PetscScalar *newValues=NULL,*tmpValues; 6775 PetscBool anyConstrained = PETSC_FALSE; 6776 6777 PetscFunctionBegin; 6778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6779 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6780 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6781 6782 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6783 /* if there are point-to-point constraints */ 6784 if (aSec) { 6785 PetscCall(PetscArrayzero(newOffsets, 32)); 6786 PetscCall(ISGetIndices(aIS,&anchors)); 6787 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6788 /* figure out how many points are going to be in the new element matrix 6789 * (we allow double counting, because it's all just going to be summed 6790 * into the global matrix anyway) */ 6791 for (p = 0; p < 2*numPoints; p+=2) { 6792 PetscInt b = points[p]; 6793 PetscInt bDof = 0, bSecDof; 6794 6795 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6796 if (!bSecDof) { 6797 continue; 6798 } 6799 if (b >= aStart && b < aEnd) { 6800 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6801 } 6802 if (bDof) { 6803 /* this point is constrained */ 6804 /* it is going to be replaced by its anchors */ 6805 PetscInt bOff, q; 6806 6807 anyConstrained = PETSC_TRUE; 6808 newNumPoints += bDof; 6809 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6810 for (q = 0; q < bDof; q++) { 6811 PetscInt a = anchors[bOff + q]; 6812 PetscInt aDof; 6813 6814 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6815 newNumIndices += aDof; 6816 for (f = 0; f < numFields; ++f) { 6817 PetscInt fDof; 6818 6819 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6820 newOffsets[f+1] += fDof; 6821 } 6822 } 6823 } 6824 else { 6825 /* this point is not constrained */ 6826 newNumPoints++; 6827 newNumIndices += bSecDof; 6828 for (f = 0; f < numFields; ++f) { 6829 PetscInt fDof; 6830 6831 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6832 newOffsets[f+1] += fDof; 6833 } 6834 } 6835 } 6836 } 6837 if (!anyConstrained) { 6838 if (outNumPoints) *outNumPoints = 0; 6839 if (outNumIndices) *outNumIndices = 0; 6840 if (outPoints) *outPoints = NULL; 6841 if (outValues) *outValues = NULL; 6842 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6843 PetscFunctionReturn(0); 6844 } 6845 6846 if (outNumPoints) *outNumPoints = newNumPoints; 6847 if (outNumIndices) *outNumIndices = newNumIndices; 6848 6849 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6850 6851 if (!outPoints && !outValues) { 6852 if (offsets) { 6853 for (f = 0; f <= numFields; f++) { 6854 offsets[f] = newOffsets[f]; 6855 } 6856 } 6857 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6858 PetscFunctionReturn(0); 6859 } 6860 6861 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6862 6863 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6864 6865 /* workspaces */ 6866 if (numFields) { 6867 for (f = 0; f < numFields; f++) { 6868 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6869 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6870 } 6871 } 6872 else { 6873 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6874 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6875 } 6876 6877 /* get workspaces for the point-to-point matrices */ 6878 if (numFields) { 6879 PetscInt totalOffset, totalMatOffset; 6880 6881 for (p = 0; p < numPoints; p++) { 6882 PetscInt b = points[2*p]; 6883 PetscInt bDof = 0, bSecDof; 6884 6885 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6886 if (!bSecDof) { 6887 for (f = 0; f < numFields; f++) { 6888 newPointOffsets[f][p + 1] = 0; 6889 pointMatOffsets[f][p + 1] = 0; 6890 } 6891 continue; 6892 } 6893 if (b >= aStart && b < aEnd) { 6894 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6895 } 6896 if (bDof) { 6897 for (f = 0; f < numFields; f++) { 6898 PetscInt fDof, q, bOff, allFDof = 0; 6899 6900 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6901 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6902 for (q = 0; q < bDof; q++) { 6903 PetscInt a = anchors[bOff + q]; 6904 PetscInt aFDof; 6905 6906 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6907 allFDof += aFDof; 6908 } 6909 newPointOffsets[f][p+1] = allFDof; 6910 pointMatOffsets[f][p+1] = fDof * allFDof; 6911 } 6912 } 6913 else { 6914 for (f = 0; f < numFields; f++) { 6915 PetscInt fDof; 6916 6917 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6918 newPointOffsets[f][p+1] = fDof; 6919 pointMatOffsets[f][p+1] = 0; 6920 } 6921 } 6922 } 6923 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6924 newPointOffsets[f][0] = totalOffset; 6925 pointMatOffsets[f][0] = totalMatOffset; 6926 for (p = 0; p < numPoints; p++) { 6927 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6928 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6929 } 6930 totalOffset = newPointOffsets[f][numPoints]; 6931 totalMatOffset = pointMatOffsets[f][numPoints]; 6932 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6933 } 6934 } 6935 else { 6936 for (p = 0; p < numPoints; p++) { 6937 PetscInt b = points[2*p]; 6938 PetscInt bDof = 0, bSecDof; 6939 6940 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6941 if (!bSecDof) { 6942 newPointOffsets[0][p + 1] = 0; 6943 pointMatOffsets[0][p + 1] = 0; 6944 continue; 6945 } 6946 if (b >= aStart && b < aEnd) { 6947 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6948 } 6949 if (bDof) { 6950 PetscInt bOff, q, allDof = 0; 6951 6952 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6953 for (q = 0; q < bDof; q++) { 6954 PetscInt a = anchors[bOff + q], aDof; 6955 6956 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6957 allDof += aDof; 6958 } 6959 newPointOffsets[0][p+1] = allDof; 6960 pointMatOffsets[0][p+1] = bSecDof * allDof; 6961 } 6962 else { 6963 newPointOffsets[0][p+1] = bSecDof; 6964 pointMatOffsets[0][p+1] = 0; 6965 } 6966 } 6967 newPointOffsets[0][0] = 0; 6968 pointMatOffsets[0][0] = 0; 6969 for (p = 0; p < numPoints; p++) { 6970 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6971 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6972 } 6973 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6974 } 6975 6976 /* output arrays */ 6977 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6978 6979 /* get the point-to-point matrices; construct newPoints */ 6980 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6981 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6982 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6983 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6984 if (numFields) { 6985 for (p = 0, newP = 0; p < numPoints; p++) { 6986 PetscInt b = points[2*p]; 6987 PetscInt o = points[2*p+1]; 6988 PetscInt bDof = 0, bSecDof; 6989 6990 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6991 if (!bSecDof) { 6992 continue; 6993 } 6994 if (b >= aStart && b < aEnd) { 6995 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6996 } 6997 if (bDof) { 6998 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6999 7000 fStart[0] = 0; 7001 fEnd[0] = 0; 7002 for (f = 0; f < numFields; f++) { 7003 PetscInt fDof; 7004 7005 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7006 fStart[f+1] = fStart[f] + fDof; 7007 fEnd[f+1] = fStart[f+1]; 7008 } 7009 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7010 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7011 7012 fAnchorStart[0] = 0; 7013 fAnchorEnd[0] = 0; 7014 for (f = 0; f < numFields; f++) { 7015 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7016 7017 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7018 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7019 } 7020 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7021 for (q = 0; q < bDof; q++) { 7022 PetscInt a = anchors[bOff + q], aOff; 7023 7024 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7025 newPoints[2*(newP + q)] = a; 7026 newPoints[2*(newP + q) + 1] = 0; 7027 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7028 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7029 } 7030 newP += bDof; 7031 7032 if (outValues) { 7033 /* get the point-to-point submatrix */ 7034 for (f = 0; f < numFields; f++) { 7035 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7036 } 7037 } 7038 } 7039 else { 7040 newPoints[2 * newP] = b; 7041 newPoints[2 * newP + 1] = o; 7042 newP++; 7043 } 7044 } 7045 } else { 7046 for (p = 0; p < numPoints; p++) { 7047 PetscInt b = points[2*p]; 7048 PetscInt o = points[2*p+1]; 7049 PetscInt bDof = 0, bSecDof; 7050 7051 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7052 if (!bSecDof) { 7053 continue; 7054 } 7055 if (b >= aStart && b < aEnd) { 7056 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7057 } 7058 if (bDof) { 7059 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7060 7061 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7062 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7063 7064 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7065 for (q = 0; q < bDof; q++) { 7066 PetscInt a = anchors[bOff + q], aOff; 7067 7068 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7069 7070 newPoints[2*(newP + q)] = a; 7071 newPoints[2*(newP + q) + 1] = 0; 7072 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7073 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7074 } 7075 newP += bDof; 7076 7077 /* get the point-to-point submatrix */ 7078 if (outValues) { 7079 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7080 } 7081 } 7082 else { 7083 newPoints[2 * newP] = b; 7084 newPoints[2 * newP + 1] = o; 7085 newP++; 7086 } 7087 } 7088 } 7089 7090 if (outValues) { 7091 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7092 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7093 /* multiply constraints on the right */ 7094 if (numFields) { 7095 for (f = 0; f < numFields; f++) { 7096 PetscInt oldOff = offsets[f]; 7097 7098 for (p = 0; p < numPoints; p++) { 7099 PetscInt cStart = newPointOffsets[f][p]; 7100 PetscInt b = points[2 * p]; 7101 PetscInt c, r, k; 7102 PetscInt dof; 7103 7104 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7105 if (!dof) { 7106 continue; 7107 } 7108 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7109 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7110 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7111 7112 for (r = 0; r < numIndices; r++) { 7113 for (c = 0; c < nCols; c++) { 7114 for (k = 0; k < dof; k++) { 7115 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7116 } 7117 } 7118 } 7119 } 7120 else { 7121 /* copy this column as is */ 7122 for (r = 0; r < numIndices; r++) { 7123 for (c = 0; c < dof; c++) { 7124 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7125 } 7126 } 7127 } 7128 oldOff += dof; 7129 } 7130 } 7131 } 7132 else { 7133 PetscInt oldOff = 0; 7134 for (p = 0; p < numPoints; p++) { 7135 PetscInt cStart = newPointOffsets[0][p]; 7136 PetscInt b = points[2 * p]; 7137 PetscInt c, r, k; 7138 PetscInt dof; 7139 7140 PetscCall(PetscSectionGetDof(section,b,&dof)); 7141 if (!dof) { 7142 continue; 7143 } 7144 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7145 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7146 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7147 7148 for (r = 0; r < numIndices; r++) { 7149 for (c = 0; c < nCols; c++) { 7150 for (k = 0; k < dof; k++) { 7151 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7152 } 7153 } 7154 } 7155 } 7156 else { 7157 /* copy this column as is */ 7158 for (r = 0; r < numIndices; r++) { 7159 for (c = 0; c < dof; c++) { 7160 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7161 } 7162 } 7163 } 7164 oldOff += dof; 7165 } 7166 } 7167 7168 if (multiplyLeft) { 7169 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7170 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7171 /* multiply constraints transpose on the left */ 7172 if (numFields) { 7173 for (f = 0; f < numFields; f++) { 7174 PetscInt oldOff = offsets[f]; 7175 7176 for (p = 0; p < numPoints; p++) { 7177 PetscInt rStart = newPointOffsets[f][p]; 7178 PetscInt b = points[2 * p]; 7179 PetscInt c, r, k; 7180 PetscInt dof; 7181 7182 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7183 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7184 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7185 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7186 7187 for (r = 0; r < nRows; r++) { 7188 for (c = 0; c < newNumIndices; c++) { 7189 for (k = 0; k < dof; k++) { 7190 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7191 } 7192 } 7193 } 7194 } 7195 else { 7196 /* copy this row as is */ 7197 for (r = 0; r < dof; r++) { 7198 for (c = 0; c < newNumIndices; c++) { 7199 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7200 } 7201 } 7202 } 7203 oldOff += dof; 7204 } 7205 } 7206 } 7207 else { 7208 PetscInt oldOff = 0; 7209 7210 for (p = 0; p < numPoints; p++) { 7211 PetscInt rStart = newPointOffsets[0][p]; 7212 PetscInt b = points[2 * p]; 7213 PetscInt c, r, k; 7214 PetscInt dof; 7215 7216 PetscCall(PetscSectionGetDof(section,b,&dof)); 7217 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7218 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7219 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7220 7221 for (r = 0; r < nRows; r++) { 7222 for (c = 0; c < newNumIndices; c++) { 7223 for (k = 0; k < dof; k++) { 7224 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7225 } 7226 } 7227 } 7228 } 7229 else { 7230 /* copy this row as is */ 7231 for (r = 0; r < dof; r++) { 7232 for (c = 0; c < newNumIndices; c++) { 7233 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7234 } 7235 } 7236 } 7237 oldOff += dof; 7238 } 7239 } 7240 7241 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7242 } 7243 else { 7244 newValues = tmpValues; 7245 } 7246 } 7247 7248 /* clean up */ 7249 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7250 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7251 7252 if (numFields) { 7253 for (f = 0; f < numFields; f++) { 7254 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7255 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7256 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7257 } 7258 } 7259 else { 7260 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7261 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7262 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7263 } 7264 PetscCall(ISRestoreIndices(aIS,&anchors)); 7265 7266 /* output */ 7267 if (outPoints) { 7268 *outPoints = newPoints; 7269 } 7270 else { 7271 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7272 } 7273 if (outValues) { 7274 *outValues = newValues; 7275 } 7276 for (f = 0; f <= numFields; f++) { 7277 offsets[f] = newOffsets[f]; 7278 } 7279 PetscFunctionReturn(0); 7280 } 7281 7282 /*@C 7283 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7284 7285 Not collective 7286 7287 Input Parameters: 7288 + dm - The DM 7289 . section - The PetscSection describing the points (a local section) 7290 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7291 . point - The point defining the closure 7292 - useClPerm - Use the closure point permutation if available 7293 7294 Output Parameters: 7295 + numIndices - The number of dof indices in the closure of point with the input sections 7296 . indices - The dof indices 7297 . outOffsets - Array to write the field offsets into, or NULL 7298 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7299 7300 Notes: 7301 Must call DMPlexRestoreClosureIndices() to free allocated memory 7302 7303 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7304 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7305 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7306 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7307 indices (with the above semantics) are implied. 7308 7309 Level: advanced 7310 7311 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7312 @*/ 7313 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7314 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7315 { 7316 /* Closure ordering */ 7317 PetscSection clSection; 7318 IS clPoints; 7319 const PetscInt *clp; 7320 PetscInt *points; 7321 const PetscInt *clperm = NULL; 7322 /* Dof permutation and sign flips */ 7323 const PetscInt **perms[32] = {NULL}; 7324 const PetscScalar **flips[32] = {NULL}; 7325 PetscScalar *valCopy = NULL; 7326 /* Hanging node constraints */ 7327 PetscInt *pointsC = NULL; 7328 PetscScalar *valuesC = NULL; 7329 PetscInt NclC, NiC; 7330 7331 PetscInt *idx; 7332 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7333 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7334 7335 PetscFunctionBeginHot; 7336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7337 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7338 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7339 if (numIndices) PetscValidIntPointer(numIndices, 6); 7340 if (indices) PetscValidPointer(indices, 7); 7341 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7342 if (values) PetscValidPointer(values, 9); 7343 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7344 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7345 PetscCall(PetscArrayzero(offsets, 32)); 7346 /* 1) Get points in closure */ 7347 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7348 if (useClPerm) { 7349 PetscInt depth, clsize; 7350 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7351 for (clsize=0,p=0; p<Ncl; p++) { 7352 PetscInt dof; 7353 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7354 clsize += dof; 7355 } 7356 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7357 } 7358 /* 2) Get number of indices on these points and field offsets from section */ 7359 for (p = 0; p < Ncl*2; p += 2) { 7360 PetscInt dof, fdof; 7361 7362 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7363 for (f = 0; f < Nf; ++f) { 7364 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7365 offsets[f+1] += fdof; 7366 } 7367 Ni += dof; 7368 } 7369 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7370 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7371 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7372 for (f = 0; f < PetscMax(1, Nf); ++f) { 7373 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7374 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7375 /* may need to apply sign changes to the element matrix */ 7376 if (values && flips[f]) { 7377 PetscInt foffset = offsets[f]; 7378 7379 for (p = 0; p < Ncl; ++p) { 7380 PetscInt pnt = points[2*p], fdof; 7381 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7382 7383 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7384 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7385 if (flip) { 7386 PetscInt i, j, k; 7387 7388 if (!valCopy) { 7389 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7390 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7391 *values = valCopy; 7392 } 7393 for (i = 0; i < fdof; ++i) { 7394 PetscScalar fval = flip[i]; 7395 7396 for (k = 0; k < Ni; ++k) { 7397 valCopy[Ni * (foffset + i) + k] *= fval; 7398 valCopy[Ni * k + (foffset + i)] *= fval; 7399 } 7400 } 7401 } 7402 foffset += fdof; 7403 } 7404 } 7405 } 7406 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7407 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7408 if (NclC) { 7409 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7410 for (f = 0; f < PetscMax(1, Nf); ++f) { 7411 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7412 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7413 } 7414 for (f = 0; f < PetscMax(1, Nf); ++f) { 7415 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7416 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7417 } 7418 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7419 Ncl = NclC; 7420 Ni = NiC; 7421 points = pointsC; 7422 if (values) *values = valuesC; 7423 } 7424 /* 5) Calculate indices */ 7425 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7426 if (Nf) { 7427 PetscInt idxOff; 7428 PetscBool useFieldOffsets; 7429 7430 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7431 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7432 if (useFieldOffsets) { 7433 for (p = 0; p < Ncl; ++p) { 7434 const PetscInt pnt = points[p*2]; 7435 7436 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7437 } 7438 } else { 7439 for (p = 0; p < Ncl; ++p) { 7440 const PetscInt pnt = points[p*2]; 7441 7442 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7443 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7444 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7445 * global section. */ 7446 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7447 } 7448 } 7449 } else { 7450 PetscInt off = 0, idxOff; 7451 7452 for (p = 0; p < Ncl; ++p) { 7453 const PetscInt pnt = points[p*2]; 7454 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7455 7456 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7457 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7458 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7459 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7460 } 7461 } 7462 /* 6) Cleanup */ 7463 for (f = 0; f < PetscMax(1, Nf); ++f) { 7464 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7465 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7466 } 7467 if (NclC) { 7468 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7469 } else { 7470 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7471 } 7472 7473 if (numIndices) *numIndices = Ni; 7474 if (indices) *indices = idx; 7475 PetscFunctionReturn(0); 7476 } 7477 7478 /*@C 7479 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7480 7481 Not collective 7482 7483 Input Parameters: 7484 + dm - The DM 7485 . section - The PetscSection describing the points (a local section) 7486 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7487 . point - The point defining the closure 7488 - useClPerm - Use the closure point permutation if available 7489 7490 Output Parameters: 7491 + numIndices - The number of dof indices in the closure of point with the input sections 7492 . indices - The dof indices 7493 . outOffsets - Array to write the field offsets into, or NULL 7494 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7495 7496 Notes: 7497 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7498 7499 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7500 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7501 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7502 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7503 indices (with the above semantics) are implied. 7504 7505 Level: advanced 7506 7507 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7508 @*/ 7509 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7510 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7511 { 7512 PetscFunctionBegin; 7513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7514 PetscValidPointer(indices, 7); 7515 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7516 PetscFunctionReturn(0); 7517 } 7518 7519 /*@C 7520 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7521 7522 Not collective 7523 7524 Input Parameters: 7525 + dm - The DM 7526 . section - The section describing the layout in v, or NULL to use the default section 7527 . globalSection - The section describing the layout in v, or NULL to use the default global section 7528 . A - The matrix 7529 . point - The point in the DM 7530 . values - The array of values 7531 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7532 7533 Fortran Notes: 7534 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7535 7536 Level: intermediate 7537 7538 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7539 @*/ 7540 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7541 { 7542 DM_Plex *mesh = (DM_Plex*) dm->data; 7543 PetscInt *indices; 7544 PetscInt numIndices; 7545 const PetscScalar *valuesOrig = values; 7546 PetscErrorCode ierr; 7547 7548 PetscFunctionBegin; 7549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7550 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7551 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7552 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7553 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7554 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7555 7556 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7557 7558 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7559 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7560 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7561 if (ierr) { 7562 PetscMPIInt rank; 7563 7564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7565 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7566 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7567 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7568 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7569 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7570 } 7571 if (mesh->printFEM > 1) { 7572 PetscInt i; 7573 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7574 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7575 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7576 } 7577 7578 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7579 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7580 PetscFunctionReturn(0); 7581 } 7582 7583 /*@C 7584 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7585 7586 Not collective 7587 7588 Input Parameters: 7589 + dmRow - The DM for the row fields 7590 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7591 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7592 . dmCol - The DM for the column fields 7593 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7594 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7595 . A - The matrix 7596 . point - The point in the DMs 7597 . values - The array of values 7598 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7599 7600 Level: intermediate 7601 7602 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7603 @*/ 7604 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7605 { 7606 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7607 PetscInt *indicesRow, *indicesCol; 7608 PetscInt numIndicesRow, numIndicesCol; 7609 const PetscScalar *valuesOrig = values; 7610 PetscErrorCode ierr; 7611 7612 PetscFunctionBegin; 7613 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7614 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7615 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7616 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7617 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7618 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7619 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7620 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7621 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7622 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7623 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7624 7625 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7626 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7627 7628 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7629 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7630 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7631 if (ierr) { 7632 PetscMPIInt rank; 7633 7634 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7635 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7636 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7637 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7638 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7639 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7640 } 7641 7642 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7643 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7644 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7645 PetscFunctionReturn(0); 7646 } 7647 7648 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7649 { 7650 DM_Plex *mesh = (DM_Plex*) dmf->data; 7651 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7652 PetscInt *cpoints = NULL; 7653 PetscInt *findices, *cindices; 7654 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7655 PetscInt foffsets[32], coffsets[32]; 7656 DMPolytopeType ct; 7657 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7658 PetscErrorCode ierr; 7659 7660 PetscFunctionBegin; 7661 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7662 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7663 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7664 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7665 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7666 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7667 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7668 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7669 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7670 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7671 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7672 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7673 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7674 PetscCall(PetscArrayzero(foffsets, 32)); 7675 PetscCall(PetscArrayzero(coffsets, 32)); 7676 /* Column indices */ 7677 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7678 maxFPoints = numCPoints; 7679 /* Compress out points not in the section */ 7680 /* TODO: Squeeze out points with 0 dof as well */ 7681 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7682 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7683 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7684 cpoints[q*2] = cpoints[p]; 7685 cpoints[q*2+1] = cpoints[p+1]; 7686 ++q; 7687 } 7688 } 7689 numCPoints = q; 7690 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7691 PetscInt fdof; 7692 7693 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7694 if (!dof) continue; 7695 for (f = 0; f < numFields; ++f) { 7696 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7697 coffsets[f+1] += fdof; 7698 } 7699 numCIndices += dof; 7700 } 7701 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7702 /* Row indices */ 7703 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7704 { 7705 DMPlexTransform tr; 7706 DMPolytopeType *rct; 7707 PetscInt *rsize, *rcone, *rornt, Nt; 7708 7709 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7710 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7711 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7712 numSubcells = rsize[Nt-1]; 7713 PetscCall(DMPlexTransformDestroy(&tr)); 7714 } 7715 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7716 for (r = 0, q = 0; r < numSubcells; ++r) { 7717 /* TODO Map from coarse to fine cells */ 7718 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7719 /* Compress out points not in the section */ 7720 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7721 for (p = 0; p < numFPoints*2; p += 2) { 7722 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7723 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7724 if (!dof) continue; 7725 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7726 if (s < q) continue; 7727 ftotpoints[q*2] = fpoints[p]; 7728 ftotpoints[q*2+1] = fpoints[p+1]; 7729 ++q; 7730 } 7731 } 7732 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7733 } 7734 numFPoints = q; 7735 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7736 PetscInt fdof; 7737 7738 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7739 if (!dof) continue; 7740 for (f = 0; f < numFields; ++f) { 7741 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7742 foffsets[f+1] += fdof; 7743 } 7744 numFIndices += dof; 7745 } 7746 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7747 7748 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7749 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7750 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7751 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7752 if (numFields) { 7753 const PetscInt **permsF[32] = {NULL}; 7754 const PetscInt **permsC[32] = {NULL}; 7755 7756 for (f = 0; f < numFields; f++) { 7757 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7758 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7759 } 7760 for (p = 0; p < numFPoints; p++) { 7761 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7762 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7763 } 7764 for (p = 0; p < numCPoints; p++) { 7765 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7766 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7767 } 7768 for (f = 0; f < numFields; f++) { 7769 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7770 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7771 } 7772 } else { 7773 const PetscInt **permsF = NULL; 7774 const PetscInt **permsC = NULL; 7775 7776 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7777 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7778 for (p = 0, off = 0; p < numFPoints; p++) { 7779 const PetscInt *perm = permsF ? permsF[p] : NULL; 7780 7781 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7782 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7783 } 7784 for (p = 0, off = 0; p < numCPoints; p++) { 7785 const PetscInt *perm = permsC ? permsC[p] : NULL; 7786 7787 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7788 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7789 } 7790 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7791 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7792 } 7793 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7794 /* TODO: flips */ 7795 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7796 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7797 if (ierr) { 7798 PetscMPIInt rank; 7799 7800 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7801 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7802 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7803 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7804 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7805 } 7806 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7807 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7808 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7809 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7810 PetscFunctionReturn(0); 7811 } 7812 7813 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7814 { 7815 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7816 PetscInt *cpoints = NULL; 7817 PetscInt foffsets[32], coffsets[32]; 7818 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7819 DMPolytopeType ct; 7820 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7821 7822 PetscFunctionBegin; 7823 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7824 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7825 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7826 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7827 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7828 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7829 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7830 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7831 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7832 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7833 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7834 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7835 PetscCall(PetscArrayzero(foffsets, 32)); 7836 PetscCall(PetscArrayzero(coffsets, 32)); 7837 /* Column indices */ 7838 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7839 maxFPoints = numCPoints; 7840 /* Compress out points not in the section */ 7841 /* TODO: Squeeze out points with 0 dof as well */ 7842 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7843 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7844 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7845 cpoints[q*2] = cpoints[p]; 7846 cpoints[q*2+1] = cpoints[p+1]; 7847 ++q; 7848 } 7849 } 7850 numCPoints = q; 7851 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7852 PetscInt fdof; 7853 7854 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7855 if (!dof) continue; 7856 for (f = 0; f < numFields; ++f) { 7857 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7858 coffsets[f+1] += fdof; 7859 } 7860 numCIndices += dof; 7861 } 7862 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7863 /* Row indices */ 7864 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7865 { 7866 DMPlexTransform tr; 7867 DMPolytopeType *rct; 7868 PetscInt *rsize, *rcone, *rornt, Nt; 7869 7870 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7871 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7872 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7873 numSubcells = rsize[Nt-1]; 7874 PetscCall(DMPlexTransformDestroy(&tr)); 7875 } 7876 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7877 for (r = 0, q = 0; r < numSubcells; ++r) { 7878 /* TODO Map from coarse to fine cells */ 7879 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7880 /* Compress out points not in the section */ 7881 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7882 for (p = 0; p < numFPoints*2; p += 2) { 7883 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7884 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7885 if (!dof) continue; 7886 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7887 if (s < q) continue; 7888 ftotpoints[q*2] = fpoints[p]; 7889 ftotpoints[q*2+1] = fpoints[p+1]; 7890 ++q; 7891 } 7892 } 7893 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7894 } 7895 numFPoints = q; 7896 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7897 PetscInt fdof; 7898 7899 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7900 if (!dof) continue; 7901 for (f = 0; f < numFields; ++f) { 7902 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7903 foffsets[f+1] += fdof; 7904 } 7905 numFIndices += dof; 7906 } 7907 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7908 7909 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7910 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7911 if (numFields) { 7912 const PetscInt **permsF[32] = {NULL}; 7913 const PetscInt **permsC[32] = {NULL}; 7914 7915 for (f = 0; f < numFields; f++) { 7916 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7917 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7918 } 7919 for (p = 0; p < numFPoints; p++) { 7920 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7921 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7922 } 7923 for (p = 0; p < numCPoints; p++) { 7924 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7925 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7926 } 7927 for (f = 0; f < numFields; f++) { 7928 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7929 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7930 } 7931 } else { 7932 const PetscInt **permsF = NULL; 7933 const PetscInt **permsC = NULL; 7934 7935 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7936 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7937 for (p = 0, off = 0; p < numFPoints; p++) { 7938 const PetscInt *perm = permsF ? permsF[p] : NULL; 7939 7940 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7941 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7942 } 7943 for (p = 0, off = 0; p < numCPoints; p++) { 7944 const PetscInt *perm = permsC ? permsC[p] : NULL; 7945 7946 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7947 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7948 } 7949 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7950 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7951 } 7952 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7953 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7954 PetscFunctionReturn(0); 7955 } 7956 7957 /*@C 7958 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7959 7960 Input Parameter: 7961 . dm - The DMPlex object 7962 7963 Output Parameter: 7964 . cellHeight - The height of a cell 7965 7966 Level: developer 7967 7968 .seealso `DMPlexSetVTKCellHeight()` 7969 @*/ 7970 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7971 { 7972 DM_Plex *mesh = (DM_Plex*) dm->data; 7973 7974 PetscFunctionBegin; 7975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7976 PetscValidIntPointer(cellHeight, 2); 7977 *cellHeight = mesh->vtkCellHeight; 7978 PetscFunctionReturn(0); 7979 } 7980 7981 /*@C 7982 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7983 7984 Input Parameters: 7985 + dm - The DMPlex object 7986 - cellHeight - The height of a cell 7987 7988 Level: developer 7989 7990 .seealso `DMPlexGetVTKCellHeight()` 7991 @*/ 7992 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7993 { 7994 DM_Plex *mesh = (DM_Plex*) dm->data; 7995 7996 PetscFunctionBegin; 7997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7998 mesh->vtkCellHeight = cellHeight; 7999 PetscFunctionReturn(0); 8000 } 8001 8002 /*@ 8003 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8004 8005 Input Parameter: 8006 . dm - The DMPlex object 8007 8008 Output Parameters: 8009 + gcStart - The first ghost cell, or NULL 8010 - gcEnd - The upper bound on ghost cells, or NULL 8011 8012 Level: advanced 8013 8014 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8015 @*/ 8016 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8017 { 8018 DMLabel ctLabel; 8019 8020 PetscFunctionBegin; 8021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8022 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8023 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8024 // Reset label for fast lookup 8025 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8026 PetscFunctionReturn(0); 8027 } 8028 8029 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8030 { 8031 PetscSection section, globalSection; 8032 PetscInt *numbers, p; 8033 8034 PetscFunctionBegin; 8035 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8036 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8037 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8038 for (p = pStart; p < pEnd; ++p) { 8039 PetscCall(PetscSectionSetDof(section, p, 1)); 8040 } 8041 PetscCall(PetscSectionSetUp(section)); 8042 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8043 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8044 for (p = pStart; p < pEnd; ++p) { 8045 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8046 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8047 else numbers[p-pStart] += shift; 8048 } 8049 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8050 if (globalSize) { 8051 PetscLayout layout; 8052 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8053 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8054 PetscCall(PetscLayoutDestroy(&layout)); 8055 } 8056 PetscCall(PetscSectionDestroy(§ion)); 8057 PetscCall(PetscSectionDestroy(&globalSection)); 8058 PetscFunctionReturn(0); 8059 } 8060 8061 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8062 { 8063 PetscInt cellHeight, cStart, cEnd; 8064 8065 PetscFunctionBegin; 8066 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8067 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8068 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8069 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8070 PetscFunctionReturn(0); 8071 } 8072 8073 /*@ 8074 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8075 8076 Input Parameter: 8077 . dm - The DMPlex object 8078 8079 Output Parameter: 8080 . globalCellNumbers - Global cell numbers for all cells on this process 8081 8082 Level: developer 8083 8084 .seealso `DMPlexGetVertexNumbering()` 8085 @*/ 8086 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8087 { 8088 DM_Plex *mesh = (DM_Plex*) dm->data; 8089 8090 PetscFunctionBegin; 8091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8092 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8093 *globalCellNumbers = mesh->globalCellNumbers; 8094 PetscFunctionReturn(0); 8095 } 8096 8097 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8098 { 8099 PetscInt vStart, vEnd; 8100 8101 PetscFunctionBegin; 8102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8103 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8104 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8105 PetscFunctionReturn(0); 8106 } 8107 8108 /*@ 8109 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8110 8111 Input Parameter: 8112 . dm - The DMPlex object 8113 8114 Output Parameter: 8115 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8116 8117 Level: developer 8118 8119 .seealso `DMPlexGetCellNumbering()` 8120 @*/ 8121 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8122 { 8123 DM_Plex *mesh = (DM_Plex*) dm->data; 8124 8125 PetscFunctionBegin; 8126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8127 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8128 *globalVertexNumbers = mesh->globalVertexNumbers; 8129 PetscFunctionReturn(0); 8130 } 8131 8132 /*@ 8133 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8134 8135 Input Parameter: 8136 . dm - The DMPlex object 8137 8138 Output Parameter: 8139 . globalPointNumbers - Global numbers for all points on this process 8140 8141 Level: developer 8142 8143 .seealso `DMPlexGetCellNumbering()` 8144 @*/ 8145 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8146 { 8147 IS nums[4]; 8148 PetscInt depths[4], gdepths[4], starts[4]; 8149 PetscInt depth, d, shift = 0; 8150 8151 PetscFunctionBegin; 8152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8153 PetscCall(DMPlexGetDepth(dm, &depth)); 8154 /* For unstratified meshes use dim instead of depth */ 8155 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8156 for (d = 0; d <= depth; ++d) { 8157 PetscInt end; 8158 8159 depths[d] = depth-d; 8160 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8161 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8162 } 8163 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8164 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8165 for (d = 0; d <= depth; ++d) { 8166 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]); 8167 } 8168 for (d = 0; d <= depth; ++d) { 8169 PetscInt pStart, pEnd, gsize; 8170 8171 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8172 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8173 shift += gsize; 8174 } 8175 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8176 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8177 PetscFunctionReturn(0); 8178 } 8179 8180 /*@ 8181 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8182 8183 Input Parameter: 8184 . dm - The DMPlex object 8185 8186 Output Parameter: 8187 . ranks - The rank field 8188 8189 Options Database Keys: 8190 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8191 8192 Level: intermediate 8193 8194 .seealso: `DMView()` 8195 @*/ 8196 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8197 { 8198 DM rdm; 8199 PetscFE fe; 8200 PetscScalar *r; 8201 PetscMPIInt rank; 8202 DMPolytopeType ct; 8203 PetscInt dim, cStart, cEnd, c; 8204 PetscBool simplex; 8205 8206 PetscFunctionBeginUser; 8207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8208 PetscValidPointer(ranks, 2); 8209 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8210 PetscCall(DMClone(dm, &rdm)); 8211 PetscCall(DMGetDimension(rdm, &dim)); 8212 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8213 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8214 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8215 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8216 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8217 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8218 PetscCall(PetscFEDestroy(&fe)); 8219 PetscCall(DMCreateDS(rdm)); 8220 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8221 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8222 PetscCall(VecGetArray(*ranks, &r)); 8223 for (c = cStart; c < cEnd; ++c) { 8224 PetscScalar *lr; 8225 8226 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8227 if (lr) *lr = rank; 8228 } 8229 PetscCall(VecRestoreArray(*ranks, &r)); 8230 PetscCall(DMDestroy(&rdm)); 8231 PetscFunctionReturn(0); 8232 } 8233 8234 /*@ 8235 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8236 8237 Input Parameters: 8238 + dm - The DMPlex 8239 - label - The DMLabel 8240 8241 Output Parameter: 8242 . val - The label value field 8243 8244 Options Database Keys: 8245 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8246 8247 Level: intermediate 8248 8249 .seealso: `DMView()` 8250 @*/ 8251 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8252 { 8253 DM rdm; 8254 PetscFE fe; 8255 PetscScalar *v; 8256 PetscInt dim, cStart, cEnd, c; 8257 8258 PetscFunctionBeginUser; 8259 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8260 PetscValidPointer(label, 2); 8261 PetscValidPointer(val, 3); 8262 PetscCall(DMClone(dm, &rdm)); 8263 PetscCall(DMGetDimension(rdm, &dim)); 8264 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8265 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8266 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8267 PetscCall(PetscFEDestroy(&fe)); 8268 PetscCall(DMCreateDS(rdm)); 8269 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8270 PetscCall(DMCreateGlobalVector(rdm, val)); 8271 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8272 PetscCall(VecGetArray(*val, &v)); 8273 for (c = cStart; c < cEnd; ++c) { 8274 PetscScalar *lv; 8275 PetscInt cval; 8276 8277 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8278 PetscCall(DMLabelGetValue(label, c, &cval)); 8279 *lv = cval; 8280 } 8281 PetscCall(VecRestoreArray(*val, &v)); 8282 PetscCall(DMDestroy(&rdm)); 8283 PetscFunctionReturn(0); 8284 } 8285 8286 /*@ 8287 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8288 8289 Input Parameter: 8290 . dm - The DMPlex object 8291 8292 Notes: 8293 This is a useful diagnostic when creating meshes programmatically. 8294 8295 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8296 8297 Level: developer 8298 8299 .seealso: `DMCreate()`, `DMSetFromOptions()` 8300 @*/ 8301 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8302 { 8303 PetscSection coneSection, supportSection; 8304 const PetscInt *cone, *support; 8305 PetscInt coneSize, c, supportSize, s; 8306 PetscInt pStart, pEnd, p, pp, csize, ssize; 8307 PetscBool storagecheck = PETSC_TRUE; 8308 8309 PetscFunctionBegin; 8310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8311 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8312 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8313 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8314 /* Check that point p is found in the support of its cone points, and vice versa */ 8315 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8316 for (p = pStart; p < pEnd; ++p) { 8317 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8318 PetscCall(DMPlexGetCone(dm, p, &cone)); 8319 for (c = 0; c < coneSize; ++c) { 8320 PetscBool dup = PETSC_FALSE; 8321 PetscInt d; 8322 for (d = c-1; d >= 0; --d) { 8323 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8324 } 8325 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8326 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8327 for (s = 0; s < supportSize; ++s) { 8328 if (support[s] == p) break; 8329 } 8330 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8332 for (s = 0; s < coneSize; ++s) { 8333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8334 } 8335 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8336 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8337 for (s = 0; s < supportSize; ++s) { 8338 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8339 } 8340 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8341 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]); 8342 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8343 } 8344 } 8345 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8346 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8347 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8348 PetscCall(DMPlexGetSupport(dm, p, &support)); 8349 for (s = 0; s < supportSize; ++s) { 8350 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8351 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8352 for (c = 0; c < coneSize; ++c) { 8353 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8354 if (cone[c] != pp) { c = 0; break; } 8355 if (cone[c] == p) break; 8356 } 8357 if (c >= coneSize) { 8358 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8359 for (c = 0; c < supportSize; ++c) { 8360 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8361 } 8362 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8363 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8364 for (c = 0; c < coneSize; ++c) { 8365 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8366 } 8367 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8368 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8369 } 8370 } 8371 } 8372 if (storagecheck) { 8373 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8374 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8375 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8376 } 8377 PetscFunctionReturn(0); 8378 } 8379 8380 /* 8381 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. 8382 */ 8383 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8384 { 8385 DMPolytopeType cct; 8386 PetscInt ptpoints[4]; 8387 const PetscInt *cone, *ccone, *ptcone; 8388 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8389 8390 PetscFunctionBegin; 8391 *unsplit = 0; 8392 switch (ct) { 8393 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8394 ptpoints[npt++] = c; 8395 break; 8396 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8397 PetscCall(DMPlexGetCone(dm, c, &cone)); 8398 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8399 for (cp = 0; cp < coneSize; ++cp) { 8400 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8401 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8402 } 8403 break; 8404 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8405 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8406 PetscCall(DMPlexGetCone(dm, c, &cone)); 8407 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8408 for (cp = 0; cp < coneSize; ++cp) { 8409 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8410 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8411 for (ccp = 0; ccp < cconeSize; ++ccp) { 8412 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8413 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8414 PetscInt p; 8415 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8416 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8417 } 8418 } 8419 } 8420 break; 8421 default: break; 8422 } 8423 for (pt = 0; pt < npt; ++pt) { 8424 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8425 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8426 } 8427 PetscFunctionReturn(0); 8428 } 8429 8430 /*@ 8431 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8432 8433 Input Parameters: 8434 + dm - The DMPlex object 8435 - cellHeight - Normally 0 8436 8437 Notes: 8438 This is a useful diagnostic when creating meshes programmatically. 8439 Currently applicable only to homogeneous simplex or tensor meshes. 8440 8441 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8442 8443 Level: developer 8444 8445 .seealso: `DMCreate()`, `DMSetFromOptions()` 8446 @*/ 8447 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8448 { 8449 DMPlexInterpolatedFlag interp; 8450 DMPolytopeType ct; 8451 PetscInt vStart, vEnd, cStart, cEnd, c; 8452 8453 PetscFunctionBegin; 8454 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8455 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8456 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8457 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8458 for (c = cStart; c < cEnd; ++c) { 8459 PetscInt *closure = NULL; 8460 PetscInt coneSize, closureSize, cl, Nv = 0; 8461 8462 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8463 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8464 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8465 if (interp == DMPLEX_INTERPOLATED_FULL) { 8466 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8467 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)); 8468 } 8469 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8470 for (cl = 0; cl < closureSize*2; cl += 2) { 8471 const PetscInt p = closure[cl]; 8472 if ((p >= vStart) && (p < vEnd)) ++Nv; 8473 } 8474 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8475 /* Special Case: Tensor faces with identified vertices */ 8476 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8477 PetscInt unsplit; 8478 8479 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8480 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8481 } 8482 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)); 8483 } 8484 PetscFunctionReturn(0); 8485 } 8486 8487 /*@ 8488 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8489 8490 Collective 8491 8492 Input Parameters: 8493 + dm - The DMPlex object 8494 - cellHeight - Normally 0 8495 8496 Notes: 8497 This is a useful diagnostic when creating meshes programmatically. 8498 This routine is only relevant for meshes that are fully interpolated across all ranks. 8499 It will error out if a partially interpolated mesh is given on some rank. 8500 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8501 8502 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8503 8504 Level: developer 8505 8506 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8507 @*/ 8508 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8509 { 8510 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8511 DMPlexInterpolatedFlag interpEnum; 8512 8513 PetscFunctionBegin; 8514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8515 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8516 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8517 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8518 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8519 PetscFunctionReturn(0); 8520 } 8521 8522 PetscCall(DMGetDimension(dm, &dim)); 8523 PetscCall(DMPlexGetDepth(dm, &depth)); 8524 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8525 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8526 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8527 for (c = cStart; c < cEnd; ++c) { 8528 const PetscInt *cone, *ornt, *faceSizes, *faces; 8529 const DMPolytopeType *faceTypes; 8530 DMPolytopeType ct; 8531 PetscInt numFaces, coneSize, f; 8532 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8533 8534 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8535 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8536 if (unsplit) continue; 8537 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8538 PetscCall(DMPlexGetCone(dm, c, &cone)); 8539 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8540 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8541 for (cl = 0; cl < closureSize*2; cl += 2) { 8542 const PetscInt p = closure[cl]; 8543 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8544 } 8545 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8546 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); 8547 for (f = 0; f < numFaces; ++f) { 8548 DMPolytopeType fct; 8549 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8550 8551 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8552 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8553 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8554 const PetscInt p = fclosure[cl]; 8555 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8556 } 8557 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]); 8558 for (v = 0; v < fnumCorners; ++v) { 8559 if (fclosure[v] != faces[fOff+v]) { 8560 PetscInt v1; 8561 8562 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8563 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8564 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8565 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8566 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8567 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]); 8568 } 8569 } 8570 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8571 fOff += faceSizes[f]; 8572 } 8573 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8574 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8575 } 8576 } 8577 PetscFunctionReturn(0); 8578 } 8579 8580 /*@ 8581 DMPlexCheckGeometry - Check the geometry of mesh cells 8582 8583 Input Parameter: 8584 . dm - The DMPlex object 8585 8586 Notes: 8587 This is a useful diagnostic when creating meshes programmatically. 8588 8589 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8590 8591 Level: developer 8592 8593 .seealso: `DMCreate()`, `DMSetFromOptions()` 8594 @*/ 8595 PetscErrorCode DMPlexCheckGeometry(DM dm) 8596 { 8597 Vec coordinates; 8598 PetscReal detJ, J[9], refVol = 1.0; 8599 PetscReal vol; 8600 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8601 8602 PetscFunctionBegin; 8603 PetscCall(DMGetDimension(dm, &dim)); 8604 PetscCall(DMGetCoordinateDim(dm, &dE)); 8605 if (dim != dE) PetscFunctionReturn(0); 8606 PetscCall(DMPlexGetDepth(dm, &depth)); 8607 for (d = 0; d < dim; ++d) refVol *= 2.0; 8608 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8609 /* Make sure local coordinates are created, because that step is collective */ 8610 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8611 for (c = cStart; c < cEnd; ++c) { 8612 DMPolytopeType ct; 8613 PetscInt unsplit; 8614 PetscBool ignoreZeroVol = PETSC_FALSE; 8615 8616 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8617 switch (ct) { 8618 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8619 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8620 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8621 ignoreZeroVol = PETSC_TRUE; break; 8622 default: break; 8623 } 8624 switch (ct) { 8625 case DM_POLYTOPE_TRI_PRISM: 8626 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8627 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8628 case DM_POLYTOPE_PYRAMID: 8629 continue; 8630 default: break; 8631 } 8632 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8633 if (unsplit) continue; 8634 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8635 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); 8636 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8637 /* This should work with periodicity since DG coordinates should be used */ 8638 if (depth > 1) { 8639 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8640 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); 8641 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8642 } 8643 } 8644 PetscFunctionReturn(0); 8645 } 8646 8647 /*@ 8648 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8649 8650 Collective 8651 8652 Input Parameters: 8653 + dm - The DMPlex object 8654 - pointSF - The Point SF, or NULL for Point SF attached to DM 8655 8656 Notes: 8657 This is mainly intended for debugging/testing purposes. 8658 8659 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8660 8661 Level: developer 8662 8663 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8664 @*/ 8665 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8666 { 8667 PetscInt l, nleaves, nroots, overlap; 8668 const PetscInt *locals; 8669 const PetscSFNode *remotes; 8670 PetscBool distributed; 8671 MPI_Comm comm; 8672 PetscMPIInt rank; 8673 8674 PetscFunctionBegin; 8675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8676 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8677 else pointSF = dm->sf; 8678 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8679 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8680 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8681 { 8682 PetscMPIInt mpiFlag; 8683 8684 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8685 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8686 } 8687 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8688 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8689 if (!distributed) { 8690 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); 8691 PetscFunctionReturn(0); 8692 } 8693 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); 8694 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8695 8696 /* Check SF graph is compatible with DMPlex chart */ 8697 { 8698 PetscInt pStart, pEnd, maxLeaf; 8699 8700 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8701 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8702 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8703 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8704 } 8705 8706 /* Check Point SF has no local points referenced */ 8707 for (l = 0; l < nleaves; l++) { 8708 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); 8709 } 8710 8711 /* Check there are no cells in interface */ 8712 if (!overlap) { 8713 PetscInt cellHeight, cStart, cEnd; 8714 8715 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8716 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8717 for (l = 0; l < nleaves; ++l) { 8718 const PetscInt point = locals ? locals[l] : l; 8719 8720 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8721 } 8722 } 8723 8724 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8725 { 8726 const PetscInt *rootdegree; 8727 8728 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8729 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8730 for (l = 0; l < nleaves; ++l) { 8731 const PetscInt point = locals ? locals[l] : l; 8732 const PetscInt *cone; 8733 PetscInt coneSize, c, idx; 8734 8735 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8736 PetscCall(DMPlexGetCone(dm, point, &cone)); 8737 for (c = 0; c < coneSize; ++c) { 8738 if (!rootdegree[cone[c]]) { 8739 if (locals) { 8740 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8741 } else { 8742 idx = (cone[c] < nleaves) ? cone[c] : -1; 8743 } 8744 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8745 } 8746 } 8747 } 8748 } 8749 PetscFunctionReturn(0); 8750 } 8751 8752 /*@ 8753 DMPlexCheck - Perform various checks of Plex sanity 8754 8755 Input Parameter: 8756 . dm - The DMPlex object 8757 8758 Notes: 8759 This is a useful diagnostic when creating meshes programmatically. 8760 8761 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8762 8763 Currently does not include DMPlexCheckCellShape(). 8764 8765 Level: developer 8766 8767 .seealso: DMCreate(), DMSetFromOptions() 8768 @*/ 8769 PetscErrorCode DMPlexCheck(DM dm) 8770 { 8771 PetscInt cellHeight; 8772 8773 PetscFunctionBegin; 8774 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8775 PetscCall(DMPlexCheckSymmetry(dm)); 8776 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8777 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8778 PetscCall(DMPlexCheckGeometry(dm)); 8779 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8780 PetscCall(DMPlexCheckInterfaceCones(dm)); 8781 PetscFunctionReturn(0); 8782 } 8783 8784 typedef struct cell_stats 8785 { 8786 PetscReal min, max, sum, squaresum; 8787 PetscInt count; 8788 } cell_stats_t; 8789 8790 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8791 { 8792 PetscInt i, N = *len; 8793 8794 for (i = 0; i < N; i++) { 8795 cell_stats_t *A = (cell_stats_t *) a; 8796 cell_stats_t *B = (cell_stats_t *) b; 8797 8798 B->min = PetscMin(A->min,B->min); 8799 B->max = PetscMax(A->max,B->max); 8800 B->sum += A->sum; 8801 B->squaresum += A->squaresum; 8802 B->count += A->count; 8803 } 8804 } 8805 8806 /*@ 8807 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8808 8809 Collective on dm 8810 8811 Input Parameters: 8812 + dm - The DMPlex object 8813 . output - If true, statistics will be displayed on stdout 8814 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8815 8816 Notes: 8817 This is mainly intended for debugging/testing purposes. 8818 8819 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8820 8821 Level: developer 8822 8823 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8824 @*/ 8825 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8826 { 8827 DM dmCoarse; 8828 cell_stats_t stats, globalStats; 8829 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8830 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8831 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8832 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8833 PetscMPIInt rank,size; 8834 8835 PetscFunctionBegin; 8836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8837 stats.min = PETSC_MAX_REAL; 8838 stats.max = PETSC_MIN_REAL; 8839 stats.sum = stats.squaresum = 0.; 8840 stats.count = 0; 8841 8842 PetscCallMPI(MPI_Comm_size(comm, &size)); 8843 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8844 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8845 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8846 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8847 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8848 for (c = cStart; c < cEnd; c++) { 8849 PetscInt i; 8850 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8851 8852 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8853 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8854 for (i = 0; i < PetscSqr(cdim); ++i) { 8855 frobJ += J[i] * J[i]; 8856 frobInvJ += invJ[i] * invJ[i]; 8857 } 8858 cond2 = frobJ * frobInvJ; 8859 cond = PetscSqrtReal(cond2); 8860 8861 stats.min = PetscMin(stats.min,cond); 8862 stats.max = PetscMax(stats.max,cond); 8863 stats.sum += cond; 8864 stats.squaresum += cond2; 8865 stats.count++; 8866 if (output && cond > limit) { 8867 PetscSection coordSection; 8868 Vec coordsLocal; 8869 PetscScalar *coords = NULL; 8870 PetscInt Nv, d, clSize, cl, *closure = NULL; 8871 8872 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8873 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8874 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8875 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8876 for (i = 0; i < Nv/cdim; ++i) { 8877 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8878 for (d = 0; d < cdim; ++d) { 8879 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8880 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8881 } 8882 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8883 } 8884 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8885 for (cl = 0; cl < clSize*2; cl += 2) { 8886 const PetscInt edge = closure[cl]; 8887 8888 if ((edge >= eStart) && (edge < eEnd)) { 8889 PetscReal len; 8890 8891 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8892 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8893 } 8894 } 8895 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8896 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8897 } 8898 } 8899 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8900 8901 if (size > 1) { 8902 PetscMPIInt blockLengths[2] = {4,1}; 8903 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8904 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8905 MPI_Op statReduce; 8906 8907 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8908 PetscCallMPI(MPI_Type_commit(&statType)); 8909 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8910 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8911 PetscCallMPI(MPI_Op_free(&statReduce)); 8912 PetscCallMPI(MPI_Type_free(&statType)); 8913 } else { 8914 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8915 } 8916 if (rank == 0) { 8917 count = globalStats.count; 8918 min = globalStats.min; 8919 max = globalStats.max; 8920 mean = globalStats.sum / globalStats.count; 8921 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8922 } 8923 8924 if (output) { 8925 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)); 8926 } 8927 PetscCall(PetscFree2(J,invJ)); 8928 8929 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8930 if (dmCoarse) { 8931 PetscBool isplex; 8932 8933 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8934 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8935 } 8936 PetscFunctionReturn(0); 8937 } 8938 8939 /*@ 8940 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8941 orthogonal quality below given tolerance. 8942 8943 Collective on dm 8944 8945 Input Parameters: 8946 + dm - The DMPlex object 8947 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8948 - atol - [0, 1] Absolute tolerance for tagging cells. 8949 8950 Output Parameters: 8951 + OrthQual - Vec containing orthogonal quality per cell 8952 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8953 8954 Options Database Keys: 8955 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8956 supported. 8957 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8958 8959 Notes: 8960 Orthogonal quality is given by the following formula: 8961 8962 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8963 8964 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 8965 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8966 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8967 calculating the cosine of the angle between these vectors. 8968 8969 Orthogonal quality ranges from 1 (best) to 0 (worst). 8970 8971 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8972 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8973 8974 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8975 8976 Level: intermediate 8977 8978 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8979 @*/ 8980 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8981 { 8982 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8983 PetscInt *idx; 8984 PetscScalar *oqVals; 8985 const PetscScalar *cellGeomArr, *faceGeomArr; 8986 PetscReal *ci, *fi, *Ai; 8987 MPI_Comm comm; 8988 Vec cellgeom, facegeom; 8989 DM dmFace, dmCell; 8990 IS glob; 8991 ISLocalToGlobalMapping ltog; 8992 PetscViewer vwr; 8993 8994 PetscFunctionBegin; 8995 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8996 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8997 PetscValidPointer(OrthQual, 4); 8998 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8999 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9000 PetscCall(DMGetDimension(dm, &nc)); 9001 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9002 { 9003 DMPlexInterpolatedFlag interpFlag; 9004 9005 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9006 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9007 PetscMPIInt rank; 9008 9009 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9010 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9011 } 9012 } 9013 if (OrthQualLabel) { 9014 PetscValidPointer(OrthQualLabel, 5); 9015 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9016 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9017 } else {*OrthQualLabel = NULL;} 9018 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9019 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9020 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9021 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9022 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9023 PetscCall(VecCreate(comm, OrthQual)); 9024 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9025 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9026 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9027 PetscCall(VecSetUp(*OrthQual)); 9028 PetscCall(ISDestroy(&glob)); 9029 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9030 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9031 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9032 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9033 PetscCall(VecGetDM(cellgeom, &dmCell)); 9034 PetscCall(VecGetDM(facegeom, &dmFace)); 9035 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9036 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9037 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9038 PetscInt cellarr[2], *adj = NULL; 9039 PetscScalar *cArr, *fArr; 9040 PetscReal minvalc = 1.0, minvalf = 1.0; 9041 PetscFVCellGeom *cg; 9042 9043 idx[cellIter] = cell-cStart; 9044 cellarr[0] = cell; 9045 /* Make indexing into cellGeom easier */ 9046 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9047 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9048 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9049 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9050 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9051 PetscInt i; 9052 const PetscInt neigh = adj[cellneigh]; 9053 PetscReal normci = 0, normfi = 0, normai = 0; 9054 PetscFVCellGeom *cgneigh; 9055 PetscFVFaceGeom *fg; 9056 9057 /* Don't count ourselves in the neighbor list */ 9058 if (neigh == cell) continue; 9059 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9060 cellarr[1] = neigh; 9061 { 9062 PetscInt numcovpts; 9063 const PetscInt *covpts; 9064 9065 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9066 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9067 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9068 } 9069 9070 /* Compute c_i, f_i and their norms */ 9071 for (i = 0; i < nc; i++) { 9072 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9073 fi[i] = fg->centroid[i] - cg->centroid[i]; 9074 Ai[i] = fg->normal[i]; 9075 normci += PetscPowReal(ci[i], 2); 9076 normfi += PetscPowReal(fi[i], 2); 9077 normai += PetscPowReal(Ai[i], 2); 9078 } 9079 normci = PetscSqrtReal(normci); 9080 normfi = PetscSqrtReal(normfi); 9081 normai = PetscSqrtReal(normai); 9082 9083 /* Normalize and compute for each face-cell-normal pair */ 9084 for (i = 0; i < nc; i++) { 9085 ci[i] = ci[i]/normci; 9086 fi[i] = fi[i]/normfi; 9087 Ai[i] = Ai[i]/normai; 9088 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9089 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9090 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9091 } 9092 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9093 minvalc = PetscRealPart(cArr[cellneighiter]); 9094 } 9095 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9096 minvalf = PetscRealPart(fArr[cellneighiter]); 9097 } 9098 } 9099 PetscCall(PetscFree(adj)); 9100 PetscCall(PetscFree2(cArr, fArr)); 9101 /* Defer to cell if they're equal */ 9102 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9103 if (OrthQualLabel) { 9104 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9105 } 9106 } 9107 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9108 PetscCall(VecAssemblyBegin(*OrthQual)); 9109 PetscCall(VecAssemblyEnd(*OrthQual)); 9110 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9111 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9112 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9113 if (OrthQualLabel) { 9114 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9115 } 9116 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9117 PetscCall(PetscViewerDestroy(&vwr)); 9118 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9119 PetscFunctionReturn(0); 9120 } 9121 9122 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9123 * interpolator construction */ 9124 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9125 { 9126 PetscSection section, newSection, gsection; 9127 PetscSF sf; 9128 PetscBool hasConstraints, ghasConstraints; 9129 9130 PetscFunctionBegin; 9131 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9132 PetscValidPointer(odm,2); 9133 PetscCall(DMGetLocalSection(dm, §ion)); 9134 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9135 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9136 if (!ghasConstraints) { 9137 PetscCall(PetscObjectReference((PetscObject)dm)); 9138 *odm = dm; 9139 PetscFunctionReturn(0); 9140 } 9141 PetscCall(DMClone(dm, odm)); 9142 PetscCall(DMCopyFields(dm, *odm)); 9143 PetscCall(DMGetLocalSection(*odm, &newSection)); 9144 PetscCall(DMGetPointSF(*odm, &sf)); 9145 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9146 PetscCall(DMSetGlobalSection(*odm, gsection)); 9147 PetscCall(PetscSectionDestroy(&gsection)); 9148 PetscFunctionReturn(0); 9149 } 9150 9151 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9152 { 9153 DM dmco, dmfo; 9154 Mat interpo; 9155 Vec rscale; 9156 Vec cglobalo, clocal; 9157 Vec fglobal, fglobalo, flocal; 9158 PetscBool regular; 9159 9160 PetscFunctionBegin; 9161 PetscCall(DMGetFullDM(dmc, &dmco)); 9162 PetscCall(DMGetFullDM(dmf, &dmfo)); 9163 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9164 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9165 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9166 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9167 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9168 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9169 PetscCall(VecSet(cglobalo, 0.)); 9170 PetscCall(VecSet(clocal, 0.)); 9171 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9172 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9173 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9174 PetscCall(VecSet(fglobal, 0.)); 9175 PetscCall(VecSet(fglobalo, 0.)); 9176 PetscCall(VecSet(flocal, 0.)); 9177 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9178 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9179 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9180 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9181 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9182 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9183 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9184 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9185 *shift = fglobal; 9186 PetscCall(VecDestroy(&flocal)); 9187 PetscCall(VecDestroy(&fglobalo)); 9188 PetscCall(VecDestroy(&clocal)); 9189 PetscCall(VecDestroy(&cglobalo)); 9190 PetscCall(VecDestroy(&rscale)); 9191 PetscCall(MatDestroy(&interpo)); 9192 PetscCall(DMDestroy(&dmfo)); 9193 PetscCall(DMDestroy(&dmco)); 9194 PetscFunctionReturn(0); 9195 } 9196 9197 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9198 { 9199 PetscObject shifto; 9200 Vec shift; 9201 9202 PetscFunctionBegin; 9203 if (!interp) { 9204 Vec rscale; 9205 9206 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9207 PetscCall(VecDestroy(&rscale)); 9208 } else { 9209 PetscCall(PetscObjectReference((PetscObject)interp)); 9210 } 9211 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9212 if (!shifto) { 9213 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9214 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9215 shifto = (PetscObject) shift; 9216 PetscCall(VecDestroy(&shift)); 9217 } 9218 shift = (Vec) shifto; 9219 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9220 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9221 PetscCall(MatDestroy(&interp)); 9222 PetscFunctionReturn(0); 9223 } 9224 9225 /* Pointwise interpolation 9226 Just code FEM for now 9227 u^f = I u^c 9228 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9229 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9230 I_{ij} = psi^f_i phi^c_j 9231 */ 9232 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9233 { 9234 PetscSection gsc, gsf; 9235 PetscInt m, n; 9236 void *ctx; 9237 DM cdm; 9238 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9239 9240 PetscFunctionBegin; 9241 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9242 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9243 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9244 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9245 9246 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9247 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9248 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9249 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9250 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9251 9252 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9253 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9254 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9255 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9256 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9257 if (scaling) { 9258 /* Use naive scaling */ 9259 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9260 } 9261 PetscFunctionReturn(0); 9262 } 9263 9264 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9265 { 9266 VecScatter ctx; 9267 9268 PetscFunctionBegin; 9269 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9270 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9271 PetscCall(VecScatterDestroy(&ctx)); 9272 PetscFunctionReturn(0); 9273 } 9274 9275 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9276 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9277 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9278 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9279 { 9280 const PetscInt Nc = uOff[1] - uOff[0]; 9281 PetscInt c; 9282 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9283 } 9284 9285 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9286 { 9287 DM dmc; 9288 PetscDS ds; 9289 Vec ones, locmass; 9290 IS cellIS; 9291 PetscFormKey key; 9292 PetscInt depth; 9293 9294 PetscFunctionBegin; 9295 PetscCall(DMClone(dm, &dmc)); 9296 PetscCall(DMCopyDisc(dm, dmc)); 9297 PetscCall(DMGetDS(dmc, &ds)); 9298 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9299 PetscCall(DMCreateGlobalVector(dmc, mass)); 9300 PetscCall(DMGetLocalVector(dmc, &ones)); 9301 PetscCall(DMGetLocalVector(dmc, &locmass)); 9302 PetscCall(DMPlexGetDepth(dmc, &depth)); 9303 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9304 PetscCall(VecSet(locmass, 0.0)); 9305 PetscCall(VecSet(ones, 1.0)); 9306 key.label = NULL; 9307 key.value = 0; 9308 key.field = 0; 9309 key.part = 0; 9310 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9311 PetscCall(ISDestroy(&cellIS)); 9312 PetscCall(VecSet(*mass, 0.0)); 9313 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9314 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9315 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9316 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9317 PetscCall(DMDestroy(&dmc)); 9318 PetscFunctionReturn(0); 9319 } 9320 9321 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9322 { 9323 PetscSection gsc, gsf; 9324 PetscInt m, n; 9325 void *ctx; 9326 DM cdm; 9327 PetscBool regular; 9328 9329 PetscFunctionBegin; 9330 if (dmFine == dmCoarse) { 9331 DM dmc; 9332 PetscDS ds; 9333 PetscWeakForm wf; 9334 Vec u; 9335 IS cellIS; 9336 PetscFormKey key; 9337 PetscInt depth; 9338 9339 PetscCall(DMClone(dmFine, &dmc)); 9340 PetscCall(DMCopyDisc(dmFine, dmc)); 9341 PetscCall(DMGetDS(dmc, &ds)); 9342 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9343 PetscCall(PetscWeakFormClear(wf)); 9344 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9345 PetscCall(DMCreateMatrix(dmc, mass)); 9346 PetscCall(DMGetLocalVector(dmc, &u)); 9347 PetscCall(DMPlexGetDepth(dmc, &depth)); 9348 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9349 PetscCall(MatZeroEntries(*mass)); 9350 key.label = NULL; 9351 key.value = 0; 9352 key.field = 0; 9353 key.part = 0; 9354 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9355 PetscCall(ISDestroy(&cellIS)); 9356 PetscCall(DMRestoreLocalVector(dmc, &u)); 9357 PetscCall(DMDestroy(&dmc)); 9358 } else { 9359 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9360 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9361 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9362 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9363 9364 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9365 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9366 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9367 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9368 9369 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9370 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9371 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9372 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9373 } 9374 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9375 PetscFunctionReturn(0); 9376 } 9377 9378 /*@ 9379 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9380 9381 Input Parameter: 9382 . dm - The DMPlex object 9383 9384 Output Parameter: 9385 . regular - The flag 9386 9387 Level: intermediate 9388 9389 .seealso: `DMPlexSetRegularRefinement()` 9390 @*/ 9391 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9392 { 9393 PetscFunctionBegin; 9394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9395 PetscValidBoolPointer(regular, 2); 9396 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9397 PetscFunctionReturn(0); 9398 } 9399 9400 /*@ 9401 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9402 9403 Input Parameters: 9404 + dm - The DMPlex object 9405 - regular - The flag 9406 9407 Level: intermediate 9408 9409 .seealso: `DMPlexGetRegularRefinement()` 9410 @*/ 9411 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9412 { 9413 PetscFunctionBegin; 9414 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9415 ((DM_Plex *) dm->data)->regularRefinement = regular; 9416 PetscFunctionReturn(0); 9417 } 9418 9419 /* anchors */ 9420 /*@ 9421 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9422 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9423 9424 not collective 9425 9426 Input Parameter: 9427 . dm - The DMPlex object 9428 9429 Output Parameters: 9430 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9431 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9432 9433 Level: intermediate 9434 9435 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9436 @*/ 9437 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9438 { 9439 DM_Plex *plex = (DM_Plex *)dm->data; 9440 9441 PetscFunctionBegin; 9442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9443 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9444 if (anchorSection) *anchorSection = plex->anchorSection; 9445 if (anchorIS) *anchorIS = plex->anchorIS; 9446 PetscFunctionReturn(0); 9447 } 9448 9449 /*@ 9450 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9451 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9452 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9453 9454 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9455 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9456 9457 collective on dm 9458 9459 Input Parameters: 9460 + dm - The DMPlex object 9461 . 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). 9462 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9463 9464 The reference counts of anchorSection and anchorIS are incremented. 9465 9466 Level: intermediate 9467 9468 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9469 @*/ 9470 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9471 { 9472 DM_Plex *plex = (DM_Plex *)dm->data; 9473 PetscMPIInt result; 9474 9475 PetscFunctionBegin; 9476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9477 if (anchorSection) { 9478 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9479 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9480 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9481 } 9482 if (anchorIS) { 9483 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9484 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9485 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9486 } 9487 9488 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9489 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9490 plex->anchorSection = anchorSection; 9491 9492 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9493 PetscCall(ISDestroy(&plex->anchorIS)); 9494 plex->anchorIS = anchorIS; 9495 9496 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9497 PetscInt size, a, pStart, pEnd; 9498 const PetscInt *anchors; 9499 9500 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9501 PetscCall(ISGetLocalSize(anchorIS,&size)); 9502 PetscCall(ISGetIndices(anchorIS,&anchors)); 9503 for (a = 0; a < size; a++) { 9504 PetscInt p; 9505 9506 p = anchors[a]; 9507 if (p >= pStart && p < pEnd) { 9508 PetscInt dof; 9509 9510 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9511 if (dof) { 9512 9513 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9514 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9515 } 9516 } 9517 } 9518 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9519 } 9520 /* reset the generic constraints */ 9521 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9522 PetscFunctionReturn(0); 9523 } 9524 9525 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9526 { 9527 PetscSection anchorSection; 9528 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9529 9530 PetscFunctionBegin; 9531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9532 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9533 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9534 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9535 if (numFields) { 9536 PetscInt f; 9537 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9538 9539 for (f = 0; f < numFields; f++) { 9540 PetscInt numComp; 9541 9542 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9543 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9544 } 9545 } 9546 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9547 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9548 pStart = PetscMax(pStart,sStart); 9549 pEnd = PetscMin(pEnd,sEnd); 9550 pEnd = PetscMax(pStart,pEnd); 9551 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9552 for (p = pStart; p < pEnd; p++) { 9553 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9554 if (dof) { 9555 PetscCall(PetscSectionGetDof(section,p,&dof)); 9556 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9557 for (f = 0; f < numFields; f++) { 9558 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9559 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9560 } 9561 } 9562 } 9563 PetscCall(PetscSectionSetUp(*cSec)); 9564 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9565 PetscFunctionReturn(0); 9566 } 9567 9568 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9569 { 9570 PetscSection aSec; 9571 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9572 const PetscInt *anchors; 9573 PetscInt numFields, f; 9574 IS aIS; 9575 MatType mtype; 9576 PetscBool iscuda,iskokkos; 9577 9578 PetscFunctionBegin; 9579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9580 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9581 PetscCall(PetscSectionGetStorageSize(section, &n)); 9582 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9583 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9584 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9585 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9586 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9587 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9588 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9589 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9590 else mtype = MATSEQAIJ; 9591 PetscCall(MatSetType(*cMat,mtype)); 9592 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9593 PetscCall(ISGetIndices(aIS,&anchors)); 9594 /* cSec will be a subset of aSec and section */ 9595 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9596 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9597 PetscCall(PetscMalloc1(m+1,&i)); 9598 i[0] = 0; 9599 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9600 for (p = pStart; p < pEnd; p++) { 9601 PetscInt rDof, rOff, r; 9602 9603 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9604 if (!rDof) continue; 9605 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9606 if (numFields) { 9607 for (f = 0; f < numFields; f++) { 9608 annz = 0; 9609 for (r = 0; r < rDof; r++) { 9610 a = anchors[rOff + r]; 9611 if (a < sStart || a >= sEnd) continue; 9612 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9613 annz += aDof; 9614 } 9615 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9616 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9617 for (q = 0; q < dof; q++) { 9618 i[off + q + 1] = i[off + q] + annz; 9619 } 9620 } 9621 } else { 9622 annz = 0; 9623 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9624 for (q = 0; q < dof; q++) { 9625 a = anchors[rOff + q]; 9626 if (a < sStart || a >= sEnd) continue; 9627 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9628 annz += aDof; 9629 } 9630 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9631 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9632 for (q = 0; q < dof; q++) { 9633 i[off + q + 1] = i[off + q] + annz; 9634 } 9635 } 9636 } 9637 nnz = i[m]; 9638 PetscCall(PetscMalloc1(nnz,&j)); 9639 offset = 0; 9640 for (p = pStart; p < pEnd; p++) { 9641 if (numFields) { 9642 for (f = 0; f < numFields; f++) { 9643 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9644 for (q = 0; q < dof; q++) { 9645 PetscInt rDof, rOff, r; 9646 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9647 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9648 for (r = 0; r < rDof; r++) { 9649 PetscInt s; 9650 9651 a = anchors[rOff + r]; 9652 if (a < sStart || a >= sEnd) continue; 9653 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9654 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9655 for (s = 0; s < aDof; s++) { 9656 j[offset++] = aOff + s; 9657 } 9658 } 9659 } 9660 } 9661 } else { 9662 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9663 for (q = 0; q < dof; q++) { 9664 PetscInt rDof, rOff, r; 9665 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9666 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9667 for (r = 0; r < rDof; r++) { 9668 PetscInt s; 9669 9670 a = anchors[rOff + r]; 9671 if (a < sStart || a >= sEnd) continue; 9672 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9673 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9674 for (s = 0; s < aDof; s++) { 9675 j[offset++] = aOff + s; 9676 } 9677 } 9678 } 9679 } 9680 } 9681 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9682 PetscCall(PetscFree(i)); 9683 PetscCall(PetscFree(j)); 9684 PetscCall(ISRestoreIndices(aIS,&anchors)); 9685 PetscFunctionReturn(0); 9686 } 9687 9688 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9689 { 9690 DM_Plex *plex = (DM_Plex *)dm->data; 9691 PetscSection anchorSection, section, cSec; 9692 Mat cMat; 9693 9694 PetscFunctionBegin; 9695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9696 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9697 if (anchorSection) { 9698 PetscInt Nf; 9699 9700 PetscCall(DMGetLocalSection(dm,§ion)); 9701 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9702 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9703 PetscCall(DMGetNumFields(dm,&Nf)); 9704 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9705 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9706 PetscCall(PetscSectionDestroy(&cSec)); 9707 PetscCall(MatDestroy(&cMat)); 9708 } 9709 PetscFunctionReturn(0); 9710 } 9711 9712 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9713 { 9714 IS subis; 9715 PetscSection section, subsection; 9716 9717 PetscFunctionBegin; 9718 PetscCall(DMGetLocalSection(dm, §ion)); 9719 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9720 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9721 /* Create subdomain */ 9722 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9723 /* Create submodel */ 9724 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9725 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9726 PetscCall(DMSetLocalSection(*subdm, subsection)); 9727 PetscCall(PetscSectionDestroy(&subsection)); 9728 PetscCall(DMCopyDisc(dm, *subdm)); 9729 /* Create map from submodel to global model */ 9730 if (is) { 9731 PetscSection sectionGlobal, subsectionGlobal; 9732 IS spIS; 9733 const PetscInt *spmap; 9734 PetscInt *subIndices; 9735 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9736 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9737 9738 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9739 PetscCall(ISGetIndices(spIS, &spmap)); 9740 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9741 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9742 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9743 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9744 for (p = pStart; p < pEnd; ++p) { 9745 PetscInt gdof, pSubSize = 0; 9746 9747 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9748 if (gdof > 0) { 9749 for (f = 0; f < Nf; ++f) { 9750 PetscInt fdof, fcdof; 9751 9752 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9753 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9754 pSubSize += fdof-fcdof; 9755 } 9756 subSize += pSubSize; 9757 if (pSubSize) { 9758 if (bs < 0) { 9759 bs = pSubSize; 9760 } else if (bs != pSubSize) { 9761 /* Layout does not admit a pointwise block size */ 9762 bs = 1; 9763 } 9764 } 9765 } 9766 } 9767 /* Must have same blocksize on all procs (some might have no points) */ 9768 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9769 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9770 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9771 else {bs = bsMinMax[0];} 9772 PetscCall(PetscMalloc1(subSize, &subIndices)); 9773 for (p = pStart; p < pEnd; ++p) { 9774 PetscInt gdof, goff; 9775 9776 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9777 if (gdof > 0) { 9778 const PetscInt point = spmap[p]; 9779 9780 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9781 for (f = 0; f < Nf; ++f) { 9782 PetscInt fdof, fcdof, fc, f2, poff = 0; 9783 9784 /* Can get rid of this loop by storing field information in the global section */ 9785 for (f2 = 0; f2 < f; ++f2) { 9786 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9787 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9788 poff += fdof-fcdof; 9789 } 9790 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9791 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9792 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9793 subIndices[subOff] = goff+poff+fc; 9794 } 9795 } 9796 } 9797 } 9798 PetscCall(ISRestoreIndices(spIS, &spmap)); 9799 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9800 if (bs > 1) { 9801 /* We need to check that the block size does not come from non-contiguous fields */ 9802 PetscInt i, j, set = 1; 9803 for (i = 0; i < subSize; i += bs) { 9804 for (j = 0; j < bs; ++j) { 9805 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9806 } 9807 } 9808 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9809 } 9810 /* Attach nullspace */ 9811 for (f = 0; f < Nf; ++f) { 9812 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9813 if ((*subdm)->nullspaceConstructors[f]) break; 9814 } 9815 if (f < Nf) { 9816 MatNullSpace nullSpace; 9817 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9818 9819 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9820 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9821 } 9822 } 9823 PetscFunctionReturn(0); 9824 } 9825 9826 /*@ 9827 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9828 9829 Input Parameter: 9830 - dm - The DM 9831 9832 Level: developer 9833 9834 Options Database Keys: 9835 . -dm_plex_monitor_throughput - Activate the monitor 9836 9837 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9838 @*/ 9839 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9840 { 9841 #if defined(PETSC_USE_LOG) 9842 PetscStageLog stageLog; 9843 PetscLogEvent event; 9844 PetscLogStage stage; 9845 PetscEventPerfInfo eventInfo; 9846 PetscReal cellRate, flopRate; 9847 PetscInt cStart, cEnd, Nf, N; 9848 const char *name; 9849 #endif 9850 9851 PetscFunctionBegin; 9852 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9853 #if defined(PETSC_USE_LOG) 9854 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9855 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9856 PetscCall(DMGetNumFields(dm, &Nf)); 9857 PetscCall(PetscLogGetStageLog(&stageLog)); 9858 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9859 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9860 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9861 N = (cEnd - cStart)*Nf*eventInfo.count; 9862 flopRate = eventInfo.flops/eventInfo.time; 9863 cellRate = N/eventInfo.time; 9864 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))); 9865 #else 9866 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9867 #endif 9868 PetscFunctionReturn(0); 9869 } 9870