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, *vArray; 5527 const PetscInt *cone, *coneO; 5528 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5529 5530 PetscFunctionBeginHot; 5531 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5532 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5533 PetscCall(DMPlexGetCone(dm, point, &cone)); 5534 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5535 if (!values || !*values) { 5536 if ((point >= pStart) && (point < pEnd)) { 5537 PetscInt dof; 5538 5539 PetscCall(PetscSectionGetDof(section, point, &dof)); 5540 size += dof; 5541 } 5542 for (p = 0; p < numPoints; ++p) { 5543 const PetscInt cp = cone[p]; 5544 PetscInt dof; 5545 5546 if ((cp < pStart) || (cp >= pEnd)) continue; 5547 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5548 size += dof; 5549 } 5550 if (!values) { 5551 if (csize) *csize = size; 5552 PetscFunctionReturn(0); 5553 } 5554 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5555 } else { 5556 array = *values; 5557 } 5558 size = 0; 5559 PetscCall(VecGetArray(v, &vArray)); 5560 if ((point >= pStart) && (point < pEnd)) { 5561 PetscInt dof, off, d; 5562 PetscScalar *varr; 5563 5564 PetscCall(PetscSectionGetDof(section, point, &dof)); 5565 PetscCall(PetscSectionGetOffset(section, point, &off)); 5566 varr = &vArray[off]; 5567 for (d = 0; d < dof; ++d, ++offset) { 5568 array[offset] = varr[d]; 5569 } 5570 size += dof; 5571 } 5572 for (p = 0; p < numPoints; ++p) { 5573 const PetscInt cp = cone[p]; 5574 PetscInt o = coneO[p]; 5575 PetscInt dof, off, d; 5576 PetscScalar *varr; 5577 5578 if ((cp < pStart) || (cp >= pEnd)) continue; 5579 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5580 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5581 varr = &vArray[off]; 5582 if (o >= 0) { 5583 for (d = 0; d < dof; ++d, ++offset) { 5584 array[offset] = varr[d]; 5585 } 5586 } else { 5587 for (d = dof-1; d >= 0; --d, ++offset) { 5588 array[offset] = varr[d]; 5589 } 5590 } 5591 size += dof; 5592 } 5593 PetscCall(VecRestoreArray(v, &vArray)); 5594 if (!*values) { 5595 if (csize) *csize = size; 5596 *values = array; 5597 } else { 5598 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5599 *csize = size; 5600 } 5601 PetscFunctionReturn(0); 5602 } 5603 5604 /* Compress out points not in the section */ 5605 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5606 { 5607 const PetscInt np = *numPoints; 5608 PetscInt pStart, pEnd, p, q; 5609 5610 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5611 for (p = 0, q = 0; p < np; ++p) { 5612 const PetscInt r = points[p*2]; 5613 if ((r >= pStart) && (r < pEnd)) { 5614 points[q*2] = r; 5615 points[q*2+1] = points[p*2+1]; 5616 ++q; 5617 } 5618 } 5619 *numPoints = q; 5620 return 0; 5621 } 5622 5623 /* Compressed closure does not apply closure permutation */ 5624 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5625 { 5626 const PetscInt *cla = NULL; 5627 PetscInt np, *pts = NULL; 5628 5629 PetscFunctionBeginHot; 5630 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5631 if (*clPoints) { 5632 PetscInt dof, off; 5633 5634 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5635 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5636 PetscCall(ISGetIndices(*clPoints, &cla)); 5637 np = dof/2; 5638 pts = (PetscInt *) &cla[off]; 5639 } else { 5640 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5641 PetscCall(CompressPoints_Private(section, &np, pts)); 5642 } 5643 *numPoints = np; 5644 *points = pts; 5645 *clp = cla; 5646 PetscFunctionReturn(0); 5647 } 5648 5649 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5650 { 5651 PetscFunctionBeginHot; 5652 if (!*clPoints) { 5653 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5654 } else { 5655 PetscCall(ISRestoreIndices(*clPoints, clp)); 5656 } 5657 *numPoints = 0; 5658 *points = NULL; 5659 *clSec = NULL; 5660 *clPoints = NULL; 5661 *clp = NULL; 5662 PetscFunctionReturn(0); 5663 } 5664 5665 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5666 { 5667 PetscInt offset = 0, p; 5668 const PetscInt **perms = NULL; 5669 const PetscScalar **flips = NULL; 5670 5671 PetscFunctionBeginHot; 5672 *size = 0; 5673 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5674 for (p = 0; p < numPoints; p++) { 5675 const PetscInt point = points[2*p]; 5676 const PetscInt *perm = perms ? perms[p] : NULL; 5677 const PetscScalar *flip = flips ? flips[p] : NULL; 5678 PetscInt dof, off, d; 5679 const PetscScalar *varr; 5680 5681 PetscCall(PetscSectionGetDof(section, point, &dof)); 5682 PetscCall(PetscSectionGetOffset(section, point, &off)); 5683 varr = &vArray[off]; 5684 if (clperm) { 5685 if (perm) { 5686 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5687 } else { 5688 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5689 } 5690 if (flip) { 5691 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5692 } 5693 } else { 5694 if (perm) { 5695 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5696 } else { 5697 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5698 } 5699 if (flip) { 5700 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5701 } 5702 } 5703 offset += dof; 5704 } 5705 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5706 *size = offset; 5707 PetscFunctionReturn(0); 5708 } 5709 5710 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[]) 5711 { 5712 PetscInt offset = 0, f; 5713 5714 PetscFunctionBeginHot; 5715 *size = 0; 5716 for (f = 0; f < numFields; ++f) { 5717 PetscInt p; 5718 const PetscInt **perms = NULL; 5719 const PetscScalar **flips = NULL; 5720 5721 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5722 for (p = 0; p < numPoints; p++) { 5723 const PetscInt point = points[2*p]; 5724 PetscInt fdof, foff, b; 5725 const PetscScalar *varr; 5726 const PetscInt *perm = perms ? perms[p] : NULL; 5727 const PetscScalar *flip = flips ? flips[p] : NULL; 5728 5729 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5730 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5731 varr = &vArray[foff]; 5732 if (clperm) { 5733 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5734 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5735 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5736 } else { 5737 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5738 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5739 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5740 } 5741 offset += fdof; 5742 } 5743 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5744 } 5745 *size = offset; 5746 PetscFunctionReturn(0); 5747 } 5748 5749 /*@C 5750 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5751 5752 Not collective 5753 5754 Input Parameters: 5755 + dm - The DM 5756 . section - The section describing the layout in v, or NULL to use the default section 5757 . v - The local vector 5758 - point - The point in the DM 5759 5760 Input/Output Parameters: 5761 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5762 - values - An array to use for the values, or NULL to have it allocated automatically; 5763 if the user provided NULL, it is a borrowed array and should not be freed 5764 5765 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5766 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5767 $ assembly function, and a user may already have allocated storage for this operation. 5768 $ 5769 $ A typical use could be 5770 $ 5771 $ values = NULL; 5772 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5773 $ for (cl = 0; cl < clSize; ++cl) { 5774 $ <Compute on closure> 5775 $ } 5776 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5777 $ 5778 $ or 5779 $ 5780 $ PetscMalloc1(clMaxSize, &values); 5781 $ for (p = pStart; p < pEnd; ++p) { 5782 $ clSize = clMaxSize; 5783 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5784 $ for (cl = 0; cl < clSize; ++cl) { 5785 $ <Compute on closure> 5786 $ } 5787 $ } 5788 $ PetscFree(values); 5789 5790 Fortran Notes: 5791 Since it returns an array, this routine is only available in Fortran 90, and you must 5792 include petsc.h90 in your code. 5793 5794 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5795 5796 Level: intermediate 5797 5798 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5799 @*/ 5800 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5801 { 5802 PetscSection clSection; 5803 IS clPoints; 5804 PetscInt *points = NULL; 5805 const PetscInt *clp, *perm; 5806 PetscInt depth, numFields, numPoints, asize; 5807 5808 PetscFunctionBeginHot; 5809 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5810 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5811 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5812 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5813 PetscCall(DMPlexGetDepth(dm, &depth)); 5814 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5815 if (depth == 1 && numFields < 2) { 5816 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5817 PetscFunctionReturn(0); 5818 } 5819 /* Get points */ 5820 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5821 /* Get sizes */ 5822 asize = 0; 5823 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5824 PetscInt dof; 5825 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5826 asize += dof; 5827 } 5828 if (values) { 5829 const PetscScalar *vArray; 5830 PetscInt size; 5831 5832 if (*values) { 5833 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); 5834 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5835 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5836 PetscCall(VecGetArrayRead(v, &vArray)); 5837 /* Get values */ 5838 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5839 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5840 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5841 /* Cleanup array */ 5842 PetscCall(VecRestoreArrayRead(v, &vArray)); 5843 } 5844 if (csize) *csize = asize; 5845 /* Cleanup points */ 5846 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5847 PetscFunctionReturn(0); 5848 } 5849 5850 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5851 { 5852 DMLabel depthLabel; 5853 PetscSection clSection; 5854 IS clPoints; 5855 PetscScalar *array; 5856 const PetscScalar *vArray; 5857 PetscInt *points = NULL; 5858 const PetscInt *clp, *perm = NULL; 5859 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5860 5861 PetscFunctionBeginHot; 5862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5863 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5864 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5865 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5866 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5867 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5868 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5869 if (mdepth == 1 && numFields < 2) { 5870 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5871 PetscFunctionReturn(0); 5872 } 5873 /* Get points */ 5874 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5875 for (clsize=0,p=0; p<Np; p++) { 5876 PetscInt dof; 5877 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5878 clsize += dof; 5879 } 5880 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5881 /* Filter points */ 5882 for (p = 0; p < numPoints*2; p += 2) { 5883 PetscInt dep; 5884 5885 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5886 if (dep != depth) continue; 5887 points[Np*2+0] = points[p]; 5888 points[Np*2+1] = points[p+1]; 5889 ++Np; 5890 } 5891 /* Get array */ 5892 if (!values || !*values) { 5893 PetscInt asize = 0, dof; 5894 5895 for (p = 0; p < Np*2; p += 2) { 5896 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5897 asize += dof; 5898 } 5899 if (!values) { 5900 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5901 if (csize) *csize = asize; 5902 PetscFunctionReturn(0); 5903 } 5904 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5905 } else { 5906 array = *values; 5907 } 5908 PetscCall(VecGetArrayRead(v, &vArray)); 5909 /* Get values */ 5910 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5911 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5912 /* Cleanup points */ 5913 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5914 /* Cleanup array */ 5915 PetscCall(VecRestoreArrayRead(v, &vArray)); 5916 if (!*values) { 5917 if (csize) *csize = size; 5918 *values = array; 5919 } else { 5920 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5921 *csize = size; 5922 } 5923 PetscFunctionReturn(0); 5924 } 5925 5926 /*@C 5927 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5928 5929 Not collective 5930 5931 Input Parameters: 5932 + dm - The DM 5933 . section - The section describing the layout in v, or NULL to use the default section 5934 . v - The local vector 5935 . point - The point in the DM 5936 . csize - The number of values in the closure, or NULL 5937 - values - The array of values, which is a borrowed array and should not be freed 5938 5939 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5940 5941 Fortran Notes: 5942 Since it returns an array, this routine is only available in Fortran 90, and you must 5943 include petsc.h90 in your code. 5944 5945 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5946 5947 Level: intermediate 5948 5949 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5950 @*/ 5951 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5952 { 5953 PetscInt size = 0; 5954 5955 PetscFunctionBegin; 5956 /* Should work without recalculating size */ 5957 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5958 *values = NULL; 5959 PetscFunctionReturn(0); 5960 } 5961 5962 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5963 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5964 5965 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[]) 5966 { 5967 PetscInt cdof; /* The number of constraints on this point */ 5968 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5969 PetscScalar *a; 5970 PetscInt off, cind = 0, k; 5971 5972 PetscFunctionBegin; 5973 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5974 PetscCall(PetscSectionGetOffset(section, point, &off)); 5975 a = &array[off]; 5976 if (!cdof || setBC) { 5977 if (clperm) { 5978 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5979 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5980 } else { 5981 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5982 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5983 } 5984 } else { 5985 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5986 if (clperm) { 5987 if (perm) {for (k = 0; k < dof; ++k) { 5988 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5989 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5990 } 5991 } else { 5992 for (k = 0; k < dof; ++k) { 5993 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5994 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5995 } 5996 } 5997 } else { 5998 if (perm) { 5999 for (k = 0; k < dof; ++k) { 6000 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6001 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6002 } 6003 } else { 6004 for (k = 0; k < dof; ++k) { 6005 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6006 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6007 } 6008 } 6009 } 6010 } 6011 PetscFunctionReturn(0); 6012 } 6013 6014 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[]) 6015 { 6016 PetscInt cdof; /* The number of constraints on this point */ 6017 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6018 PetscScalar *a; 6019 PetscInt off, cind = 0, k; 6020 6021 PetscFunctionBegin; 6022 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6023 PetscCall(PetscSectionGetOffset(section, point, &off)); 6024 a = &array[off]; 6025 if (cdof) { 6026 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6027 if (clperm) { 6028 if (perm) { 6029 for (k = 0; k < dof; ++k) { 6030 if ((cind < cdof) && (k == cdofs[cind])) { 6031 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6032 cind++; 6033 } 6034 } 6035 } else { 6036 for (k = 0; k < dof; ++k) { 6037 if ((cind < cdof) && (k == cdofs[cind])) { 6038 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6039 cind++; 6040 } 6041 } 6042 } 6043 } else { 6044 if (perm) { 6045 for (k = 0; k < dof; ++k) { 6046 if ((cind < cdof) && (k == cdofs[cind])) { 6047 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6048 cind++; 6049 } 6050 } 6051 } else { 6052 for (k = 0; k < dof; ++k) { 6053 if ((cind < cdof) && (k == cdofs[cind])) { 6054 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6055 cind++; 6056 } 6057 } 6058 } 6059 } 6060 } 6061 PetscFunctionReturn(0); 6062 } 6063 6064 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[]) 6065 { 6066 PetscScalar *a; 6067 PetscInt fdof, foff, fcdof, foffset = *offset; 6068 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6069 PetscInt cind = 0, b; 6070 6071 PetscFunctionBegin; 6072 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6073 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6074 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6075 a = &array[foff]; 6076 if (!fcdof || setBC) { 6077 if (clperm) { 6078 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6079 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6080 } else { 6081 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6082 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6083 } 6084 } else { 6085 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6086 if (clperm) { 6087 if (perm) { 6088 for (b = 0; b < fdof; b++) { 6089 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6090 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6091 } 6092 } else { 6093 for (b = 0; b < fdof; b++) { 6094 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6095 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6096 } 6097 } 6098 } else { 6099 if (perm) { 6100 for (b = 0; b < fdof; b++) { 6101 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6102 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6103 } 6104 } else { 6105 for (b = 0; b < fdof; b++) { 6106 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6107 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6108 } 6109 } 6110 } 6111 } 6112 *offset += fdof; 6113 PetscFunctionReturn(0); 6114 } 6115 6116 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[]) 6117 { 6118 PetscScalar *a; 6119 PetscInt fdof, foff, fcdof, foffset = *offset; 6120 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6121 PetscInt Nc, cind = 0, ncind = 0, b; 6122 PetscBool ncSet, fcSet; 6123 6124 PetscFunctionBegin; 6125 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6126 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6127 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6128 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6129 a = &array[foff]; 6130 if (fcdof) { 6131 /* We just override fcdof and fcdofs with Ncc and comps */ 6132 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6133 if (clperm) { 6134 if (perm) { 6135 if (comps) { 6136 for (b = 0; b < fdof; b++) { 6137 ncSet = fcSet = PETSC_FALSE; 6138 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6139 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6140 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6141 } 6142 } else { 6143 for (b = 0; b < fdof; b++) { 6144 if ((cind < fcdof) && (b == fcdofs[cind])) { 6145 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6146 ++cind; 6147 } 6148 } 6149 } 6150 } else { 6151 if (comps) { 6152 for (b = 0; b < fdof; b++) { 6153 ncSet = fcSet = PETSC_FALSE; 6154 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6155 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6156 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6157 } 6158 } else { 6159 for (b = 0; b < fdof; b++) { 6160 if ((cind < fcdof) && (b == fcdofs[cind])) { 6161 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6162 ++cind; 6163 } 6164 } 6165 } 6166 } 6167 } else { 6168 if (perm) { 6169 if (comps) { 6170 for (b = 0; b < fdof; b++) { 6171 ncSet = fcSet = PETSC_FALSE; 6172 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6173 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6174 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6175 } 6176 } else { 6177 for (b = 0; b < fdof; b++) { 6178 if ((cind < fcdof) && (b == fcdofs[cind])) { 6179 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6180 ++cind; 6181 } 6182 } 6183 } 6184 } else { 6185 if (comps) { 6186 for (b = 0; b < fdof; b++) { 6187 ncSet = fcSet = PETSC_FALSE; 6188 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6189 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6190 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6191 } 6192 } else { 6193 for (b = 0; b < fdof; b++) { 6194 if ((cind < fcdof) && (b == fcdofs[cind])) { 6195 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6196 ++cind; 6197 } 6198 } 6199 } 6200 } 6201 } 6202 } 6203 *offset += fdof; 6204 PetscFunctionReturn(0); 6205 } 6206 6207 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6208 { 6209 PetscScalar *array; 6210 const PetscInt *cone, *coneO; 6211 PetscInt pStart, pEnd, p, numPoints, off, dof; 6212 6213 PetscFunctionBeginHot; 6214 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6215 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6216 PetscCall(DMPlexGetCone(dm, point, &cone)); 6217 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6218 PetscCall(VecGetArray(v, &array)); 6219 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6220 const PetscInt cp = !p ? point : cone[p-1]; 6221 const PetscInt o = !p ? 0 : coneO[p-1]; 6222 6223 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6224 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6225 /* ADD_VALUES */ 6226 { 6227 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6228 PetscScalar *a; 6229 PetscInt cdof, coff, cind = 0, k; 6230 6231 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6232 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6233 a = &array[coff]; 6234 if (!cdof) { 6235 if (o >= 0) { 6236 for (k = 0; k < dof; ++k) { 6237 a[k] += values[off+k]; 6238 } 6239 } else { 6240 for (k = 0; k < dof; ++k) { 6241 a[k] += values[off+dof-k-1]; 6242 } 6243 } 6244 } else { 6245 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6246 if (o >= 0) { 6247 for (k = 0; k < dof; ++k) { 6248 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6249 a[k] += values[off+k]; 6250 } 6251 } else { 6252 for (k = 0; k < dof; ++k) { 6253 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6254 a[k] += values[off+dof-k-1]; 6255 } 6256 } 6257 } 6258 } 6259 } 6260 PetscCall(VecRestoreArray(v, &array)); 6261 PetscFunctionReturn(0); 6262 } 6263 6264 /*@C 6265 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6266 6267 Not collective 6268 6269 Input Parameters: 6270 + dm - The DM 6271 . section - The section describing the layout in v, or NULL to use the default section 6272 . v - The local vector 6273 . point - The point in the DM 6274 . values - The array of values 6275 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6276 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6277 6278 Fortran Notes: 6279 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6280 6281 Level: intermediate 6282 6283 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6284 @*/ 6285 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6286 { 6287 PetscSection clSection; 6288 IS clPoints; 6289 PetscScalar *array; 6290 PetscInt *points = NULL; 6291 const PetscInt *clp, *clperm = NULL; 6292 PetscInt depth, numFields, numPoints, p, clsize; 6293 6294 PetscFunctionBeginHot; 6295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6296 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6297 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6298 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6299 PetscCall(DMPlexGetDepth(dm, &depth)); 6300 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6301 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6302 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6303 PetscFunctionReturn(0); 6304 } 6305 /* Get points */ 6306 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6307 for (clsize=0,p=0; p<numPoints; p++) { 6308 PetscInt dof; 6309 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6310 clsize += dof; 6311 } 6312 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6313 /* Get array */ 6314 PetscCall(VecGetArray(v, &array)); 6315 /* Get values */ 6316 if (numFields > 0) { 6317 PetscInt offset = 0, f; 6318 for (f = 0; f < numFields; ++f) { 6319 const PetscInt **perms = NULL; 6320 const PetscScalar **flips = NULL; 6321 6322 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6323 switch (mode) { 6324 case INSERT_VALUES: 6325 for (p = 0; p < numPoints; p++) { 6326 const PetscInt point = points[2*p]; 6327 const PetscInt *perm = perms ? perms[p] : NULL; 6328 const PetscScalar *flip = flips ? flips[p] : NULL; 6329 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6330 } break; 6331 case INSERT_ALL_VALUES: 6332 for (p = 0; p < numPoints; p++) { 6333 const PetscInt point = points[2*p]; 6334 const PetscInt *perm = perms ? perms[p] : NULL; 6335 const PetscScalar *flip = flips ? flips[p] : NULL; 6336 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6337 } break; 6338 case INSERT_BC_VALUES: 6339 for (p = 0; p < numPoints; p++) { 6340 const PetscInt point = points[2*p]; 6341 const PetscInt *perm = perms ? perms[p] : NULL; 6342 const PetscScalar *flip = flips ? flips[p] : NULL; 6343 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6344 } break; 6345 case ADD_VALUES: 6346 for (p = 0; p < numPoints; p++) { 6347 const PetscInt point = points[2*p]; 6348 const PetscInt *perm = perms ? perms[p] : NULL; 6349 const PetscScalar *flip = flips ? flips[p] : NULL; 6350 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6351 } break; 6352 case ADD_ALL_VALUES: 6353 for (p = 0; p < numPoints; p++) { 6354 const PetscInt point = points[2*p]; 6355 const PetscInt *perm = perms ? perms[p] : NULL; 6356 const PetscScalar *flip = flips ? flips[p] : NULL; 6357 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6358 } break; 6359 case ADD_BC_VALUES: 6360 for (p = 0; p < numPoints; p++) { 6361 const PetscInt point = points[2*p]; 6362 const PetscInt *perm = perms ? perms[p] : NULL; 6363 const PetscScalar *flip = flips ? flips[p] : NULL; 6364 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6365 } break; 6366 default: 6367 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6368 } 6369 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6370 } 6371 } else { 6372 PetscInt dof, off; 6373 const PetscInt **perms = NULL; 6374 const PetscScalar **flips = NULL; 6375 6376 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6377 switch (mode) { 6378 case INSERT_VALUES: 6379 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6380 const PetscInt point = points[2*p]; 6381 const PetscInt *perm = perms ? perms[p] : NULL; 6382 const PetscScalar *flip = flips ? flips[p] : NULL; 6383 PetscCall(PetscSectionGetDof(section, point, &dof)); 6384 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6385 } break; 6386 case INSERT_ALL_VALUES: 6387 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6388 const PetscInt point = points[2*p]; 6389 const PetscInt *perm = perms ? perms[p] : NULL; 6390 const PetscScalar *flip = flips ? flips[p] : NULL; 6391 PetscCall(PetscSectionGetDof(section, point, &dof)); 6392 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6393 } break; 6394 case INSERT_BC_VALUES: 6395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6396 const PetscInt point = points[2*p]; 6397 const PetscInt *perm = perms ? perms[p] : NULL; 6398 const PetscScalar *flip = flips ? flips[p] : NULL; 6399 PetscCall(PetscSectionGetDof(section, point, &dof)); 6400 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6401 } break; 6402 case ADD_VALUES: 6403 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6404 const PetscInt point = points[2*p]; 6405 const PetscInt *perm = perms ? perms[p] : NULL; 6406 const PetscScalar *flip = flips ? flips[p] : NULL; 6407 PetscCall(PetscSectionGetDof(section, point, &dof)); 6408 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6409 } break; 6410 case ADD_ALL_VALUES: 6411 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6412 const PetscInt point = points[2*p]; 6413 const PetscInt *perm = perms ? perms[p] : NULL; 6414 const PetscScalar *flip = flips ? flips[p] : NULL; 6415 PetscCall(PetscSectionGetDof(section, point, &dof)); 6416 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6417 } break; 6418 case ADD_BC_VALUES: 6419 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6420 const PetscInt point = points[2*p]; 6421 const PetscInt *perm = perms ? perms[p] : NULL; 6422 const PetscScalar *flip = flips ? flips[p] : NULL; 6423 PetscCall(PetscSectionGetDof(section, point, &dof)); 6424 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6425 } break; 6426 default: 6427 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6428 } 6429 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6430 } 6431 /* Cleanup points */ 6432 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6433 /* Cleanup array */ 6434 PetscCall(VecRestoreArray(v, &array)); 6435 PetscFunctionReturn(0); 6436 } 6437 6438 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6439 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6440 { 6441 PetscFunctionBegin; 6442 if (label) { 6443 PetscBool contains; 6444 PetscInt fdof; 6445 6446 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6447 if (!contains) { 6448 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6449 *offset += fdof; 6450 PetscFunctionReturn(1); 6451 } 6452 } 6453 PetscFunctionReturn(0); 6454 } 6455 6456 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6457 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) 6458 { 6459 PetscSection clSection; 6460 IS clPoints; 6461 PetscScalar *array; 6462 PetscInt *points = NULL; 6463 const PetscInt *clp; 6464 PetscInt numFields, numPoints, p; 6465 PetscInt offset = 0, f; 6466 6467 PetscFunctionBeginHot; 6468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6469 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6470 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6471 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6472 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6473 /* Get points */ 6474 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6475 /* Get array */ 6476 PetscCall(VecGetArray(v, &array)); 6477 /* Get values */ 6478 for (f = 0; f < numFields; ++f) { 6479 const PetscInt **perms = NULL; 6480 const PetscScalar **flips = NULL; 6481 6482 if (!fieldActive[f]) { 6483 for (p = 0; p < numPoints*2; p += 2) { 6484 PetscInt fdof; 6485 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6486 offset += fdof; 6487 } 6488 continue; 6489 } 6490 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6491 switch (mode) { 6492 case INSERT_VALUES: 6493 for (p = 0; p < numPoints; p++) { 6494 const PetscInt point = points[2*p]; 6495 const PetscInt *perm = perms ? perms[p] : NULL; 6496 const PetscScalar *flip = flips ? flips[p] : NULL; 6497 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6498 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6499 } break; 6500 case INSERT_ALL_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2*p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6506 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6507 } break; 6508 case INSERT_BC_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2*p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6514 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6515 } break; 6516 case ADD_VALUES: 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2*p]; 6519 const PetscInt *perm = perms ? perms[p] : NULL; 6520 const PetscScalar *flip = flips ? flips[p] : NULL; 6521 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6522 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6523 } break; 6524 case ADD_ALL_VALUES: 6525 for (p = 0; p < numPoints; p++) { 6526 const PetscInt point = points[2*p]; 6527 const PetscInt *perm = perms ? perms[p] : NULL; 6528 const PetscScalar *flip = flips ? flips[p] : NULL; 6529 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6530 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6531 } break; 6532 default: 6533 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6534 } 6535 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6536 } 6537 /* Cleanup points */ 6538 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6539 /* Cleanup array */ 6540 PetscCall(VecRestoreArray(v, &array)); 6541 PetscFunctionReturn(0); 6542 } 6543 6544 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6545 { 6546 PetscMPIInt rank; 6547 PetscInt i, j; 6548 6549 PetscFunctionBegin; 6550 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6551 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6552 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6553 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6554 numCIndices = numCIndices ? numCIndices : numRIndices; 6555 if (!values) PetscFunctionReturn(0); 6556 for (i = 0; i < numRIndices; i++) { 6557 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6558 for (j = 0; j < numCIndices; j++) { 6559 #if defined(PETSC_USE_COMPLEX) 6560 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6561 #else 6562 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6563 #endif 6564 } 6565 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6566 } 6567 PetscFunctionReturn(0); 6568 } 6569 6570 /* 6571 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6572 6573 Input Parameters: 6574 + section - The section for this data layout 6575 . islocal - Is the section (and thus indices being requested) local or global? 6576 . point - The point contributing dofs with these indices 6577 . off - The global offset of this point 6578 . loff - The local offset of each field 6579 . setBC - The flag determining whether to include indices of boundary values 6580 . perm - A permutation of the dofs on this point, or NULL 6581 - indperm - A permutation of the entire indices array, or NULL 6582 6583 Output Parameter: 6584 . indices - Indices for dofs on this point 6585 6586 Level: developer 6587 6588 Note: The indices could be local or global, depending on the value of 'off'. 6589 */ 6590 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6591 { 6592 PetscInt dof; /* The number of unknowns on this point */ 6593 PetscInt cdof; /* The number of constraints on this point */ 6594 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6595 PetscInt cind = 0, k; 6596 6597 PetscFunctionBegin; 6598 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6599 PetscCall(PetscSectionGetDof(section, point, &dof)); 6600 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6601 if (!cdof || setBC) { 6602 for (k = 0; k < dof; ++k) { 6603 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6604 const PetscInt ind = indperm ? indperm[preind] : preind; 6605 6606 indices[ind] = off + k; 6607 } 6608 } else { 6609 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6610 for (k = 0; k < dof; ++k) { 6611 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6612 const PetscInt ind = indperm ? indperm[preind] : preind; 6613 6614 if ((cind < cdof) && (k == cdofs[cind])) { 6615 /* Insert check for returning constrained indices */ 6616 indices[ind] = -(off+k+1); 6617 ++cind; 6618 } else { 6619 indices[ind] = off + k - (islocal ? 0 : cind); 6620 } 6621 } 6622 } 6623 *loff += dof; 6624 PetscFunctionReturn(0); 6625 } 6626 6627 /* 6628 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6629 6630 Input Parameters: 6631 + section - a section (global or local) 6632 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6633 . point - point within section 6634 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6635 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6636 . setBC - identify constrained (boundary condition) points via involution. 6637 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6638 . permsoff - offset 6639 - indperm - index permutation 6640 6641 Output Parameter: 6642 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6643 . indices - array to hold indices (as defined by section) of each dof associated with point 6644 6645 Notes: 6646 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6647 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6648 in the local vector. 6649 6650 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6651 significant). It is invalid to call with a global section and setBC=true. 6652 6653 Developer Note: 6654 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6655 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6656 offset could be obtained from the section instead of passing it explicitly as we do now. 6657 6658 Example: 6659 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6660 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6661 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6662 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. 6663 6664 Level: developer 6665 */ 6666 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[]) 6667 { 6668 PetscInt numFields, foff, f; 6669 6670 PetscFunctionBegin; 6671 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6672 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6673 for (f = 0, foff = 0; f < numFields; ++f) { 6674 PetscInt fdof, cfdof; 6675 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6676 PetscInt cind = 0, b; 6677 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6678 6679 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6680 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6681 if (!cfdof || setBC) { 6682 for (b = 0; b < fdof; ++b) { 6683 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6684 const PetscInt ind = indperm ? indperm[preind] : preind; 6685 6686 indices[ind] = off+foff+b; 6687 } 6688 } else { 6689 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6690 for (b = 0; b < fdof; ++b) { 6691 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6692 const PetscInt ind = indperm ? indperm[preind] : preind; 6693 6694 if ((cind < cfdof) && (b == fcdofs[cind])) { 6695 indices[ind] = -(off+foff+b+1); 6696 ++cind; 6697 } else { 6698 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6699 } 6700 } 6701 } 6702 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6703 foffs[f] += fdof; 6704 } 6705 PetscFunctionReturn(0); 6706 } 6707 6708 /* 6709 This version believes the globalSection offsets for each field, rather than just the point offset 6710 6711 . foffs - The offset into 'indices' for each field, since it is segregated by field 6712 6713 Notes: 6714 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6715 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6716 */ 6717 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6718 { 6719 PetscInt numFields, foff, f; 6720 6721 PetscFunctionBegin; 6722 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6723 for (f = 0; f < numFields; ++f) { 6724 PetscInt fdof, cfdof; 6725 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6726 PetscInt cind = 0, b; 6727 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6728 6729 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6730 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6731 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6732 if (!cfdof) { 6733 for (b = 0; b < fdof; ++b) { 6734 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6735 const PetscInt ind = indperm ? indperm[preind] : preind; 6736 6737 indices[ind] = foff+b; 6738 } 6739 } else { 6740 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6741 for (b = 0; b < fdof; ++b) { 6742 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6743 const PetscInt ind = indperm ? indperm[preind] : preind; 6744 6745 if ((cind < cfdof) && (b == fcdofs[cind])) { 6746 indices[ind] = -(foff+b+1); 6747 ++cind; 6748 } else { 6749 indices[ind] = foff+b-cind; 6750 } 6751 } 6752 } 6753 foffs[f] += fdof; 6754 } 6755 PetscFunctionReturn(0); 6756 } 6757 6758 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) 6759 { 6760 Mat cMat; 6761 PetscSection aSec, cSec; 6762 IS aIS; 6763 PetscInt aStart = -1, aEnd = -1; 6764 const PetscInt *anchors; 6765 PetscInt numFields, f, p, q, newP = 0; 6766 PetscInt newNumPoints = 0, newNumIndices = 0; 6767 PetscInt *newPoints, *indices, *newIndices; 6768 PetscInt maxAnchor, maxDof; 6769 PetscInt newOffsets[32]; 6770 PetscInt *pointMatOffsets[32]; 6771 PetscInt *newPointOffsets[32]; 6772 PetscScalar *pointMat[32]; 6773 PetscScalar *newValues=NULL,*tmpValues; 6774 PetscBool anyConstrained = PETSC_FALSE; 6775 6776 PetscFunctionBegin; 6777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6778 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6779 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6780 6781 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6782 /* if there are point-to-point constraints */ 6783 if (aSec) { 6784 PetscCall(PetscArrayzero(newOffsets, 32)); 6785 PetscCall(ISGetIndices(aIS,&anchors)); 6786 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6787 /* figure out how many points are going to be in the new element matrix 6788 * (we allow double counting, because it's all just going to be summed 6789 * into the global matrix anyway) */ 6790 for (p = 0; p < 2*numPoints; p+=2) { 6791 PetscInt b = points[p]; 6792 PetscInt bDof = 0, bSecDof; 6793 6794 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6795 if (!bSecDof) { 6796 continue; 6797 } 6798 if (b >= aStart && b < aEnd) { 6799 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6800 } 6801 if (bDof) { 6802 /* this point is constrained */ 6803 /* it is going to be replaced by its anchors */ 6804 PetscInt bOff, q; 6805 6806 anyConstrained = PETSC_TRUE; 6807 newNumPoints += bDof; 6808 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6809 for (q = 0; q < bDof; q++) { 6810 PetscInt a = anchors[bOff + q]; 6811 PetscInt aDof; 6812 6813 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6814 newNumIndices += aDof; 6815 for (f = 0; f < numFields; ++f) { 6816 PetscInt fDof; 6817 6818 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6819 newOffsets[f+1] += fDof; 6820 } 6821 } 6822 } 6823 else { 6824 /* this point is not constrained */ 6825 newNumPoints++; 6826 newNumIndices += bSecDof; 6827 for (f = 0; f < numFields; ++f) { 6828 PetscInt fDof; 6829 6830 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6831 newOffsets[f+1] += fDof; 6832 } 6833 } 6834 } 6835 } 6836 if (!anyConstrained) { 6837 if (outNumPoints) *outNumPoints = 0; 6838 if (outNumIndices) *outNumIndices = 0; 6839 if (outPoints) *outPoints = NULL; 6840 if (outValues) *outValues = NULL; 6841 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6842 PetscFunctionReturn(0); 6843 } 6844 6845 if (outNumPoints) *outNumPoints = newNumPoints; 6846 if (outNumIndices) *outNumIndices = newNumIndices; 6847 6848 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6849 6850 if (!outPoints && !outValues) { 6851 if (offsets) { 6852 for (f = 0; f <= numFields; f++) { 6853 offsets[f] = newOffsets[f]; 6854 } 6855 } 6856 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6857 PetscFunctionReturn(0); 6858 } 6859 6860 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6861 6862 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6863 6864 /* workspaces */ 6865 if (numFields) { 6866 for (f = 0; f < numFields; f++) { 6867 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6868 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6869 } 6870 } 6871 else { 6872 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6873 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6874 } 6875 6876 /* get workspaces for the point-to-point matrices */ 6877 if (numFields) { 6878 PetscInt totalOffset, totalMatOffset; 6879 6880 for (p = 0; p < numPoints; p++) { 6881 PetscInt b = points[2*p]; 6882 PetscInt bDof = 0, bSecDof; 6883 6884 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6885 if (!bSecDof) { 6886 for (f = 0; f < numFields; f++) { 6887 newPointOffsets[f][p + 1] = 0; 6888 pointMatOffsets[f][p + 1] = 0; 6889 } 6890 continue; 6891 } 6892 if (b >= aStart && b < aEnd) { 6893 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6894 } 6895 if (bDof) { 6896 for (f = 0; f < numFields; f++) { 6897 PetscInt fDof, q, bOff, allFDof = 0; 6898 6899 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6900 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6901 for (q = 0; q < bDof; q++) { 6902 PetscInt a = anchors[bOff + q]; 6903 PetscInt aFDof; 6904 6905 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6906 allFDof += aFDof; 6907 } 6908 newPointOffsets[f][p+1] = allFDof; 6909 pointMatOffsets[f][p+1] = fDof * allFDof; 6910 } 6911 } 6912 else { 6913 for (f = 0; f < numFields; f++) { 6914 PetscInt fDof; 6915 6916 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6917 newPointOffsets[f][p+1] = fDof; 6918 pointMatOffsets[f][p+1] = 0; 6919 } 6920 } 6921 } 6922 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6923 newPointOffsets[f][0] = totalOffset; 6924 pointMatOffsets[f][0] = totalMatOffset; 6925 for (p = 0; p < numPoints; p++) { 6926 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6927 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6928 } 6929 totalOffset = newPointOffsets[f][numPoints]; 6930 totalMatOffset = pointMatOffsets[f][numPoints]; 6931 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6932 } 6933 } 6934 else { 6935 for (p = 0; p < numPoints; p++) { 6936 PetscInt b = points[2*p]; 6937 PetscInt bDof = 0, bSecDof; 6938 6939 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6940 if (!bSecDof) { 6941 newPointOffsets[0][p + 1] = 0; 6942 pointMatOffsets[0][p + 1] = 0; 6943 continue; 6944 } 6945 if (b >= aStart && b < aEnd) { 6946 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6947 } 6948 if (bDof) { 6949 PetscInt bOff, q, allDof = 0; 6950 6951 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6952 for (q = 0; q < bDof; q++) { 6953 PetscInt a = anchors[bOff + q], aDof; 6954 6955 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6956 allDof += aDof; 6957 } 6958 newPointOffsets[0][p+1] = allDof; 6959 pointMatOffsets[0][p+1] = bSecDof * allDof; 6960 } 6961 else { 6962 newPointOffsets[0][p+1] = bSecDof; 6963 pointMatOffsets[0][p+1] = 0; 6964 } 6965 } 6966 newPointOffsets[0][0] = 0; 6967 pointMatOffsets[0][0] = 0; 6968 for (p = 0; p < numPoints; p++) { 6969 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6970 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6971 } 6972 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6973 } 6974 6975 /* output arrays */ 6976 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6977 6978 /* get the point-to-point matrices; construct newPoints */ 6979 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6980 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6981 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6982 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6983 if (numFields) { 6984 for (p = 0, newP = 0; p < numPoints; p++) { 6985 PetscInt b = points[2*p]; 6986 PetscInt o = points[2*p+1]; 6987 PetscInt bDof = 0, bSecDof; 6988 6989 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6990 if (!bSecDof) { 6991 continue; 6992 } 6993 if (b >= aStart && b < aEnd) { 6994 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6995 } 6996 if (bDof) { 6997 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6998 6999 fStart[0] = 0; 7000 fEnd[0] = 0; 7001 for (f = 0; f < numFields; f++) { 7002 PetscInt fDof; 7003 7004 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7005 fStart[f+1] = fStart[f] + fDof; 7006 fEnd[f+1] = fStart[f+1]; 7007 } 7008 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7009 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7010 7011 fAnchorStart[0] = 0; 7012 fAnchorEnd[0] = 0; 7013 for (f = 0; f < numFields; f++) { 7014 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7015 7016 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7017 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7018 } 7019 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7020 for (q = 0; q < bDof; q++) { 7021 PetscInt a = anchors[bOff + q], aOff; 7022 7023 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7024 newPoints[2*(newP + q)] = a; 7025 newPoints[2*(newP + q) + 1] = 0; 7026 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7027 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7028 } 7029 newP += bDof; 7030 7031 if (outValues) { 7032 /* get the point-to-point submatrix */ 7033 for (f = 0; f < numFields; f++) { 7034 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7035 } 7036 } 7037 } 7038 else { 7039 newPoints[2 * newP] = b; 7040 newPoints[2 * newP + 1] = o; 7041 newP++; 7042 } 7043 } 7044 } else { 7045 for (p = 0; p < numPoints; p++) { 7046 PetscInt b = points[2*p]; 7047 PetscInt o = points[2*p+1]; 7048 PetscInt bDof = 0, bSecDof; 7049 7050 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7051 if (!bSecDof) { 7052 continue; 7053 } 7054 if (b >= aStart && b < aEnd) { 7055 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7056 } 7057 if (bDof) { 7058 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7059 7060 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7061 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7062 7063 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7064 for (q = 0; q < bDof; q++) { 7065 PetscInt a = anchors[bOff + q], aOff; 7066 7067 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7068 7069 newPoints[2*(newP + q)] = a; 7070 newPoints[2*(newP + q) + 1] = 0; 7071 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7072 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7073 } 7074 newP += bDof; 7075 7076 /* get the point-to-point submatrix */ 7077 if (outValues) { 7078 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7079 } 7080 } 7081 else { 7082 newPoints[2 * newP] = b; 7083 newPoints[2 * newP + 1] = o; 7084 newP++; 7085 } 7086 } 7087 } 7088 7089 if (outValues) { 7090 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7091 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7092 /* multiply constraints on the right */ 7093 if (numFields) { 7094 for (f = 0; f < numFields; f++) { 7095 PetscInt oldOff = offsets[f]; 7096 7097 for (p = 0; p < numPoints; p++) { 7098 PetscInt cStart = newPointOffsets[f][p]; 7099 PetscInt b = points[2 * p]; 7100 PetscInt c, r, k; 7101 PetscInt dof; 7102 7103 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7104 if (!dof) { 7105 continue; 7106 } 7107 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7108 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7109 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7110 7111 for (r = 0; r < numIndices; r++) { 7112 for (c = 0; c < nCols; c++) { 7113 for (k = 0; k < dof; k++) { 7114 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7115 } 7116 } 7117 } 7118 } 7119 else { 7120 /* copy this column as is */ 7121 for (r = 0; r < numIndices; r++) { 7122 for (c = 0; c < dof; c++) { 7123 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7124 } 7125 } 7126 } 7127 oldOff += dof; 7128 } 7129 } 7130 } 7131 else { 7132 PetscInt oldOff = 0; 7133 for (p = 0; p < numPoints; p++) { 7134 PetscInt cStart = newPointOffsets[0][p]; 7135 PetscInt b = points[2 * p]; 7136 PetscInt c, r, k; 7137 PetscInt dof; 7138 7139 PetscCall(PetscSectionGetDof(section,b,&dof)); 7140 if (!dof) { 7141 continue; 7142 } 7143 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7144 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7145 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7146 7147 for (r = 0; r < numIndices; r++) { 7148 for (c = 0; c < nCols; c++) { 7149 for (k = 0; k < dof; k++) { 7150 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7151 } 7152 } 7153 } 7154 } 7155 else { 7156 /* copy this column as is */ 7157 for (r = 0; r < numIndices; r++) { 7158 for (c = 0; c < dof; c++) { 7159 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7160 } 7161 } 7162 } 7163 oldOff += dof; 7164 } 7165 } 7166 7167 if (multiplyLeft) { 7168 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7169 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7170 /* multiply constraints transpose on the left */ 7171 if (numFields) { 7172 for (f = 0; f < numFields; f++) { 7173 PetscInt oldOff = offsets[f]; 7174 7175 for (p = 0; p < numPoints; p++) { 7176 PetscInt rStart = newPointOffsets[f][p]; 7177 PetscInt b = points[2 * p]; 7178 PetscInt c, r, k; 7179 PetscInt dof; 7180 7181 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7182 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7183 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7184 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7185 7186 for (r = 0; r < nRows; r++) { 7187 for (c = 0; c < newNumIndices; c++) { 7188 for (k = 0; k < dof; k++) { 7189 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7190 } 7191 } 7192 } 7193 } 7194 else { 7195 /* copy this row as is */ 7196 for (r = 0; r < dof; r++) { 7197 for (c = 0; c < newNumIndices; c++) { 7198 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7199 } 7200 } 7201 } 7202 oldOff += dof; 7203 } 7204 } 7205 } 7206 else { 7207 PetscInt oldOff = 0; 7208 7209 for (p = 0; p < numPoints; p++) { 7210 PetscInt rStart = newPointOffsets[0][p]; 7211 PetscInt b = points[2 * p]; 7212 PetscInt c, r, k; 7213 PetscInt dof; 7214 7215 PetscCall(PetscSectionGetDof(section,b,&dof)); 7216 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7217 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7218 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7219 7220 for (r = 0; r < nRows; r++) { 7221 for (c = 0; c < newNumIndices; c++) { 7222 for (k = 0; k < dof; k++) { 7223 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7224 } 7225 } 7226 } 7227 } 7228 else { 7229 /* copy this row as is */ 7230 for (r = 0; r < dof; r++) { 7231 for (c = 0; c < newNumIndices; c++) { 7232 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7233 } 7234 } 7235 } 7236 oldOff += dof; 7237 } 7238 } 7239 7240 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7241 } 7242 else { 7243 newValues = tmpValues; 7244 } 7245 } 7246 7247 /* clean up */ 7248 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7249 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7250 7251 if (numFields) { 7252 for (f = 0; f < numFields; f++) { 7253 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7254 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7255 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7256 } 7257 } 7258 else { 7259 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7260 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7261 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7262 } 7263 PetscCall(ISRestoreIndices(aIS,&anchors)); 7264 7265 /* output */ 7266 if (outPoints) { 7267 *outPoints = newPoints; 7268 } 7269 else { 7270 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7271 } 7272 if (outValues) { 7273 *outValues = newValues; 7274 } 7275 for (f = 0; f <= numFields; f++) { 7276 offsets[f] = newOffsets[f]; 7277 } 7278 PetscFunctionReturn(0); 7279 } 7280 7281 /*@C 7282 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7283 7284 Not collective 7285 7286 Input Parameters: 7287 + dm - The DM 7288 . section - The PetscSection describing the points (a local section) 7289 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7290 . point - The point defining the closure 7291 - useClPerm - Use the closure point permutation if available 7292 7293 Output Parameters: 7294 + numIndices - The number of dof indices in the closure of point with the input sections 7295 . indices - The dof indices 7296 . outOffsets - Array to write the field offsets into, or NULL 7297 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7298 7299 Notes: 7300 Must call DMPlexRestoreClosureIndices() to free allocated memory 7301 7302 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7303 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7304 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7305 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7306 indices (with the above semantics) are implied. 7307 7308 Level: advanced 7309 7310 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7311 @*/ 7312 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7313 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7314 { 7315 /* Closure ordering */ 7316 PetscSection clSection; 7317 IS clPoints; 7318 const PetscInt *clp; 7319 PetscInt *points; 7320 const PetscInt *clperm = NULL; 7321 /* Dof permutation and sign flips */ 7322 const PetscInt **perms[32] = {NULL}; 7323 const PetscScalar **flips[32] = {NULL}; 7324 PetscScalar *valCopy = NULL; 7325 /* Hanging node constraints */ 7326 PetscInt *pointsC = NULL; 7327 PetscScalar *valuesC = NULL; 7328 PetscInt NclC, NiC; 7329 7330 PetscInt *idx; 7331 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7332 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7333 7334 PetscFunctionBeginHot; 7335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7336 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7337 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7338 if (numIndices) PetscValidIntPointer(numIndices, 6); 7339 if (indices) PetscValidPointer(indices, 7); 7340 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7341 if (values) PetscValidPointer(values, 9); 7342 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7343 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7344 PetscCall(PetscArrayzero(offsets, 32)); 7345 /* 1) Get points in closure */ 7346 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7347 if (useClPerm) { 7348 PetscInt depth, clsize; 7349 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7350 for (clsize=0,p=0; p<Ncl; p++) { 7351 PetscInt dof; 7352 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7353 clsize += dof; 7354 } 7355 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7356 } 7357 /* 2) Get number of indices on these points and field offsets from section */ 7358 for (p = 0; p < Ncl*2; p += 2) { 7359 PetscInt dof, fdof; 7360 7361 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7362 for (f = 0; f < Nf; ++f) { 7363 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7364 offsets[f+1] += fdof; 7365 } 7366 Ni += dof; 7367 } 7368 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7369 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7370 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7371 for (f = 0; f < PetscMax(1, Nf); ++f) { 7372 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7373 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7374 /* may need to apply sign changes to the element matrix */ 7375 if (values && flips[f]) { 7376 PetscInt foffset = offsets[f]; 7377 7378 for (p = 0; p < Ncl; ++p) { 7379 PetscInt pnt = points[2*p], fdof; 7380 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7381 7382 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7383 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7384 if (flip) { 7385 PetscInt i, j, k; 7386 7387 if (!valCopy) { 7388 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7389 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7390 *values = valCopy; 7391 } 7392 for (i = 0; i < fdof; ++i) { 7393 PetscScalar fval = flip[i]; 7394 7395 for (k = 0; k < Ni; ++k) { 7396 valCopy[Ni * (foffset + i) + k] *= fval; 7397 valCopy[Ni * k + (foffset + i)] *= fval; 7398 } 7399 } 7400 } 7401 foffset += fdof; 7402 } 7403 } 7404 } 7405 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7406 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7407 if (NclC) { 7408 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7409 for (f = 0; f < PetscMax(1, Nf); ++f) { 7410 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7411 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7412 } 7413 for (f = 0; f < PetscMax(1, Nf); ++f) { 7414 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7415 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7416 } 7417 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7418 Ncl = NclC; 7419 Ni = NiC; 7420 points = pointsC; 7421 if (values) *values = valuesC; 7422 } 7423 /* 5) Calculate indices */ 7424 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7425 if (Nf) { 7426 PetscInt idxOff; 7427 PetscBool useFieldOffsets; 7428 7429 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7430 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7431 if (useFieldOffsets) { 7432 for (p = 0; p < Ncl; ++p) { 7433 const PetscInt pnt = points[p*2]; 7434 7435 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7436 } 7437 } else { 7438 for (p = 0; p < Ncl; ++p) { 7439 const PetscInt pnt = points[p*2]; 7440 7441 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7442 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7443 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7444 * global section. */ 7445 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7446 } 7447 } 7448 } else { 7449 PetscInt off = 0, idxOff; 7450 7451 for (p = 0; p < Ncl; ++p) { 7452 const PetscInt pnt = points[p*2]; 7453 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7454 7455 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7456 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7457 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7458 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7459 } 7460 } 7461 /* 6) Cleanup */ 7462 for (f = 0; f < PetscMax(1, Nf); ++f) { 7463 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7464 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7465 } 7466 if (NclC) { 7467 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7468 } else { 7469 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7470 } 7471 7472 if (numIndices) *numIndices = Ni; 7473 if (indices) *indices = idx; 7474 PetscFunctionReturn(0); 7475 } 7476 7477 /*@C 7478 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7479 7480 Not collective 7481 7482 Input Parameters: 7483 + dm - The DM 7484 . section - The PetscSection describing the points (a local section) 7485 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7486 . point - The point defining the closure 7487 - useClPerm - Use the closure point permutation if available 7488 7489 Output Parameters: 7490 + numIndices - The number of dof indices in the closure of point with the input sections 7491 . indices - The dof indices 7492 . outOffsets - Array to write the field offsets into, or NULL 7493 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7494 7495 Notes: 7496 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7497 7498 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7499 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7500 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7501 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7502 indices (with the above semantics) are implied. 7503 7504 Level: advanced 7505 7506 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7507 @*/ 7508 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7509 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7510 { 7511 PetscFunctionBegin; 7512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7513 PetscValidPointer(indices, 7); 7514 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7515 PetscFunctionReturn(0); 7516 } 7517 7518 /*@C 7519 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7520 7521 Not collective 7522 7523 Input Parameters: 7524 + dm - The DM 7525 . section - The section describing the layout in v, or NULL to use the default section 7526 . globalSection - The section describing the layout in v, or NULL to use the default global section 7527 . A - The matrix 7528 . point - The point in the DM 7529 . values - The array of values 7530 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7531 7532 Fortran Notes: 7533 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7534 7535 Level: intermediate 7536 7537 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7538 @*/ 7539 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7540 { 7541 DM_Plex *mesh = (DM_Plex*) dm->data; 7542 PetscInt *indices; 7543 PetscInt numIndices; 7544 const PetscScalar *valuesOrig = values; 7545 PetscErrorCode ierr; 7546 7547 PetscFunctionBegin; 7548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7549 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7550 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7551 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7552 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7553 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7554 7555 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7556 7557 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7558 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7559 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7560 if (ierr) { 7561 PetscMPIInt rank; 7562 7563 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7564 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7565 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7566 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7567 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7568 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7569 } 7570 if (mesh->printFEM > 1) { 7571 PetscInt i; 7572 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7573 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7574 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7575 } 7576 7577 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7578 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7579 PetscFunctionReturn(0); 7580 } 7581 7582 /*@C 7583 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7584 7585 Not collective 7586 7587 Input Parameters: 7588 + dmRow - The DM for the row fields 7589 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7590 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7591 . dmCol - The DM for the column fields 7592 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7593 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7594 . A - The matrix 7595 . point - The point in the DMs 7596 . values - The array of values 7597 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7598 7599 Level: intermediate 7600 7601 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7602 @*/ 7603 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7604 { 7605 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7606 PetscInt *indicesRow, *indicesCol; 7607 PetscInt numIndicesRow, numIndicesCol; 7608 const PetscScalar *valuesOrig = values; 7609 PetscErrorCode ierr; 7610 7611 PetscFunctionBegin; 7612 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7613 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7614 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7615 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7616 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7617 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7618 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7619 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7620 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7621 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7622 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7623 7624 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7625 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7626 7627 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7628 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7629 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7630 if (ierr) { 7631 PetscMPIInt rank; 7632 7633 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7634 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7635 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7636 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7637 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7638 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7639 } 7640 7641 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7642 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7643 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7644 PetscFunctionReturn(0); 7645 } 7646 7647 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7648 { 7649 DM_Plex *mesh = (DM_Plex*) dmf->data; 7650 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7651 PetscInt *cpoints = NULL; 7652 PetscInt *findices, *cindices; 7653 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7654 PetscInt foffsets[32], coffsets[32]; 7655 DMPolytopeType ct; 7656 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7657 PetscErrorCode ierr; 7658 7659 PetscFunctionBegin; 7660 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7661 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7662 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7663 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7664 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7665 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7666 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7667 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7668 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7669 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7670 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7671 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7672 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7673 PetscCall(PetscArrayzero(foffsets, 32)); 7674 PetscCall(PetscArrayzero(coffsets, 32)); 7675 /* Column indices */ 7676 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7677 maxFPoints = numCPoints; 7678 /* Compress out points not in the section */ 7679 /* TODO: Squeeze out points with 0 dof as well */ 7680 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7681 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7682 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7683 cpoints[q*2] = cpoints[p]; 7684 cpoints[q*2+1] = cpoints[p+1]; 7685 ++q; 7686 } 7687 } 7688 numCPoints = q; 7689 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7690 PetscInt fdof; 7691 7692 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7693 if (!dof) continue; 7694 for (f = 0; f < numFields; ++f) { 7695 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7696 coffsets[f+1] += fdof; 7697 } 7698 numCIndices += dof; 7699 } 7700 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7701 /* Row indices */ 7702 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7703 { 7704 DMPlexTransform tr; 7705 DMPolytopeType *rct; 7706 PetscInt *rsize, *rcone, *rornt, Nt; 7707 7708 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7709 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7710 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7711 numSubcells = rsize[Nt-1]; 7712 PetscCall(DMPlexTransformDestroy(&tr)); 7713 } 7714 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7715 for (r = 0, q = 0; r < numSubcells; ++r) { 7716 /* TODO Map from coarse to fine cells */ 7717 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7718 /* Compress out points not in the section */ 7719 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7720 for (p = 0; p < numFPoints*2; p += 2) { 7721 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7722 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7723 if (!dof) continue; 7724 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7725 if (s < q) continue; 7726 ftotpoints[q*2] = fpoints[p]; 7727 ftotpoints[q*2+1] = fpoints[p+1]; 7728 ++q; 7729 } 7730 } 7731 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7732 } 7733 numFPoints = q; 7734 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7735 PetscInt fdof; 7736 7737 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7738 if (!dof) continue; 7739 for (f = 0; f < numFields; ++f) { 7740 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7741 foffsets[f+1] += fdof; 7742 } 7743 numFIndices += dof; 7744 } 7745 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7746 7747 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7748 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7749 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7750 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7751 if (numFields) { 7752 const PetscInt **permsF[32] = {NULL}; 7753 const PetscInt **permsC[32] = {NULL}; 7754 7755 for (f = 0; f < numFields; f++) { 7756 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7757 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7758 } 7759 for (p = 0; p < numFPoints; p++) { 7760 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7761 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7762 } 7763 for (p = 0; p < numCPoints; p++) { 7764 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7765 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7766 } 7767 for (f = 0; f < numFields; f++) { 7768 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7769 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7770 } 7771 } else { 7772 const PetscInt **permsF = NULL; 7773 const PetscInt **permsC = NULL; 7774 7775 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7776 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7777 for (p = 0, off = 0; p < numFPoints; p++) { 7778 const PetscInt *perm = permsF ? permsF[p] : NULL; 7779 7780 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7781 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7782 } 7783 for (p = 0, off = 0; p < numCPoints; p++) { 7784 const PetscInt *perm = permsC ? permsC[p] : NULL; 7785 7786 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7787 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7788 } 7789 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7790 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7791 } 7792 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7793 /* TODO: flips */ 7794 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7795 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7796 if (ierr) { 7797 PetscMPIInt rank; 7798 7799 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7800 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7801 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7802 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7803 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7804 } 7805 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7806 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7807 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7808 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7809 PetscFunctionReturn(0); 7810 } 7811 7812 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7813 { 7814 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7815 PetscInt *cpoints = NULL; 7816 PetscInt foffsets[32], coffsets[32]; 7817 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7818 DMPolytopeType ct; 7819 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7820 7821 PetscFunctionBegin; 7822 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7823 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7824 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7825 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7826 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7827 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7828 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7829 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7830 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7831 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7832 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7833 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7834 PetscCall(PetscArrayzero(foffsets, 32)); 7835 PetscCall(PetscArrayzero(coffsets, 32)); 7836 /* Column indices */ 7837 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7838 maxFPoints = numCPoints; 7839 /* Compress out points not in the section */ 7840 /* TODO: Squeeze out points with 0 dof as well */ 7841 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7842 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7843 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7844 cpoints[q*2] = cpoints[p]; 7845 cpoints[q*2+1] = cpoints[p+1]; 7846 ++q; 7847 } 7848 } 7849 numCPoints = q; 7850 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7851 PetscInt fdof; 7852 7853 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7854 if (!dof) continue; 7855 for (f = 0; f < numFields; ++f) { 7856 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7857 coffsets[f+1] += fdof; 7858 } 7859 numCIndices += dof; 7860 } 7861 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7862 /* Row indices */ 7863 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7864 { 7865 DMPlexTransform tr; 7866 DMPolytopeType *rct; 7867 PetscInt *rsize, *rcone, *rornt, Nt; 7868 7869 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7870 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7871 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7872 numSubcells = rsize[Nt-1]; 7873 PetscCall(DMPlexTransformDestroy(&tr)); 7874 } 7875 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7876 for (r = 0, q = 0; r < numSubcells; ++r) { 7877 /* TODO Map from coarse to fine cells */ 7878 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7879 /* Compress out points not in the section */ 7880 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7881 for (p = 0; p < numFPoints*2; p += 2) { 7882 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7883 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7884 if (!dof) continue; 7885 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7886 if (s < q) continue; 7887 ftotpoints[q*2] = fpoints[p]; 7888 ftotpoints[q*2+1] = fpoints[p+1]; 7889 ++q; 7890 } 7891 } 7892 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7893 } 7894 numFPoints = q; 7895 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7896 PetscInt fdof; 7897 7898 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7899 if (!dof) continue; 7900 for (f = 0; f < numFields; ++f) { 7901 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7902 foffsets[f+1] += fdof; 7903 } 7904 numFIndices += dof; 7905 } 7906 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7907 7908 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7909 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7910 if (numFields) { 7911 const PetscInt **permsF[32] = {NULL}; 7912 const PetscInt **permsC[32] = {NULL}; 7913 7914 for (f = 0; f < numFields; f++) { 7915 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7916 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7917 } 7918 for (p = 0; p < numFPoints; p++) { 7919 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7920 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7921 } 7922 for (p = 0; p < numCPoints; p++) { 7923 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7924 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7925 } 7926 for (f = 0; f < numFields; f++) { 7927 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7928 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7929 } 7930 } else { 7931 const PetscInt **permsF = NULL; 7932 const PetscInt **permsC = NULL; 7933 7934 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7935 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7936 for (p = 0, off = 0; p < numFPoints; p++) { 7937 const PetscInt *perm = permsF ? permsF[p] : NULL; 7938 7939 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7940 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7941 } 7942 for (p = 0, off = 0; p < numCPoints; p++) { 7943 const PetscInt *perm = permsC ? permsC[p] : NULL; 7944 7945 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7946 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7947 } 7948 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7949 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7950 } 7951 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7952 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7953 PetscFunctionReturn(0); 7954 } 7955 7956 /*@C 7957 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7958 7959 Input Parameter: 7960 . dm - The DMPlex object 7961 7962 Output Parameter: 7963 . cellHeight - The height of a cell 7964 7965 Level: developer 7966 7967 .seealso `DMPlexSetVTKCellHeight()` 7968 @*/ 7969 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7970 { 7971 DM_Plex *mesh = (DM_Plex*) dm->data; 7972 7973 PetscFunctionBegin; 7974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7975 PetscValidIntPointer(cellHeight, 2); 7976 *cellHeight = mesh->vtkCellHeight; 7977 PetscFunctionReturn(0); 7978 } 7979 7980 /*@C 7981 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7982 7983 Input Parameters: 7984 + dm - The DMPlex object 7985 - cellHeight - The height of a cell 7986 7987 Level: developer 7988 7989 .seealso `DMPlexGetVTKCellHeight()` 7990 @*/ 7991 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7992 { 7993 DM_Plex *mesh = (DM_Plex*) dm->data; 7994 7995 PetscFunctionBegin; 7996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7997 mesh->vtkCellHeight = cellHeight; 7998 PetscFunctionReturn(0); 7999 } 8000 8001 /*@ 8002 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8003 8004 Input Parameter: 8005 . dm - The DMPlex object 8006 8007 Output Parameters: 8008 + gcStart - The first ghost cell, or NULL 8009 - gcEnd - The upper bound on ghost cells, or NULL 8010 8011 Level: advanced 8012 8013 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8014 @*/ 8015 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8016 { 8017 DMLabel ctLabel; 8018 8019 PetscFunctionBegin; 8020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8021 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8022 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8023 // Reset label for fast lookup 8024 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8025 PetscFunctionReturn(0); 8026 } 8027 8028 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8029 { 8030 PetscSection section, globalSection; 8031 PetscInt *numbers, p; 8032 8033 PetscFunctionBegin; 8034 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8035 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8036 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8037 for (p = pStart; p < pEnd; ++p) { 8038 PetscCall(PetscSectionSetDof(section, p, 1)); 8039 } 8040 PetscCall(PetscSectionSetUp(section)); 8041 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8042 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8043 for (p = pStart; p < pEnd; ++p) { 8044 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8045 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8046 else numbers[p-pStart] += shift; 8047 } 8048 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8049 if (globalSize) { 8050 PetscLayout layout; 8051 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8052 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8053 PetscCall(PetscLayoutDestroy(&layout)); 8054 } 8055 PetscCall(PetscSectionDestroy(§ion)); 8056 PetscCall(PetscSectionDestroy(&globalSection)); 8057 PetscFunctionReturn(0); 8058 } 8059 8060 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8061 { 8062 PetscInt cellHeight, cStart, cEnd; 8063 8064 PetscFunctionBegin; 8065 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8066 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8067 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8068 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8069 PetscFunctionReturn(0); 8070 } 8071 8072 /*@ 8073 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8074 8075 Input Parameter: 8076 . dm - The DMPlex object 8077 8078 Output Parameter: 8079 . globalCellNumbers - Global cell numbers for all cells on this process 8080 8081 Level: developer 8082 8083 .seealso `DMPlexGetVertexNumbering()` 8084 @*/ 8085 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8086 { 8087 DM_Plex *mesh = (DM_Plex*) dm->data; 8088 8089 PetscFunctionBegin; 8090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8091 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8092 *globalCellNumbers = mesh->globalCellNumbers; 8093 PetscFunctionReturn(0); 8094 } 8095 8096 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8097 { 8098 PetscInt vStart, vEnd; 8099 8100 PetscFunctionBegin; 8101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8102 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8103 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8104 PetscFunctionReturn(0); 8105 } 8106 8107 /*@ 8108 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8109 8110 Input Parameter: 8111 . dm - The DMPlex object 8112 8113 Output Parameter: 8114 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8115 8116 Level: developer 8117 8118 .seealso `DMPlexGetCellNumbering()` 8119 @*/ 8120 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8121 { 8122 DM_Plex *mesh = (DM_Plex*) dm->data; 8123 8124 PetscFunctionBegin; 8125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8126 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8127 *globalVertexNumbers = mesh->globalVertexNumbers; 8128 PetscFunctionReturn(0); 8129 } 8130 8131 /*@ 8132 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8133 8134 Input Parameter: 8135 . dm - The DMPlex object 8136 8137 Output Parameter: 8138 . globalPointNumbers - Global numbers for all points on this process 8139 8140 Level: developer 8141 8142 .seealso `DMPlexGetCellNumbering()` 8143 @*/ 8144 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8145 { 8146 IS nums[4]; 8147 PetscInt depths[4], gdepths[4], starts[4]; 8148 PetscInt depth, d, shift = 0; 8149 8150 PetscFunctionBegin; 8151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8152 PetscCall(DMPlexGetDepth(dm, &depth)); 8153 /* For unstratified meshes use dim instead of depth */ 8154 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8155 for (d = 0; d <= depth; ++d) { 8156 PetscInt end; 8157 8158 depths[d] = depth-d; 8159 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8160 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8161 } 8162 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8163 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8164 for (d = 0; d <= depth; ++d) { 8165 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]); 8166 } 8167 for (d = 0; d <= depth; ++d) { 8168 PetscInt pStart, pEnd, gsize; 8169 8170 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8171 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8172 shift += gsize; 8173 } 8174 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8175 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8176 PetscFunctionReturn(0); 8177 } 8178 8179 /*@ 8180 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8181 8182 Input Parameter: 8183 . dm - The DMPlex object 8184 8185 Output Parameter: 8186 . ranks - The rank field 8187 8188 Options Database Keys: 8189 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8190 8191 Level: intermediate 8192 8193 .seealso: `DMView()` 8194 @*/ 8195 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8196 { 8197 DM rdm; 8198 PetscFE fe; 8199 PetscScalar *r; 8200 PetscMPIInt rank; 8201 DMPolytopeType ct; 8202 PetscInt dim, cStart, cEnd, c; 8203 PetscBool simplex; 8204 8205 PetscFunctionBeginUser; 8206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8207 PetscValidPointer(ranks, 2); 8208 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8209 PetscCall(DMClone(dm, &rdm)); 8210 PetscCall(DMGetDimension(rdm, &dim)); 8211 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8212 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8213 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8214 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8215 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8216 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8217 PetscCall(PetscFEDestroy(&fe)); 8218 PetscCall(DMCreateDS(rdm)); 8219 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8220 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8221 PetscCall(VecGetArray(*ranks, &r)); 8222 for (c = cStart; c < cEnd; ++c) { 8223 PetscScalar *lr; 8224 8225 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8226 if (lr) *lr = rank; 8227 } 8228 PetscCall(VecRestoreArray(*ranks, &r)); 8229 PetscCall(DMDestroy(&rdm)); 8230 PetscFunctionReturn(0); 8231 } 8232 8233 /*@ 8234 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8235 8236 Input Parameters: 8237 + dm - The DMPlex 8238 - label - The DMLabel 8239 8240 Output Parameter: 8241 . val - The label value field 8242 8243 Options Database Keys: 8244 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8245 8246 Level: intermediate 8247 8248 .seealso: `DMView()` 8249 @*/ 8250 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8251 { 8252 DM rdm; 8253 PetscFE fe; 8254 PetscScalar *v; 8255 PetscInt dim, cStart, cEnd, c; 8256 8257 PetscFunctionBeginUser; 8258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8259 PetscValidPointer(label, 2); 8260 PetscValidPointer(val, 3); 8261 PetscCall(DMClone(dm, &rdm)); 8262 PetscCall(DMGetDimension(rdm, &dim)); 8263 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8264 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8265 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8266 PetscCall(PetscFEDestroy(&fe)); 8267 PetscCall(DMCreateDS(rdm)); 8268 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8269 PetscCall(DMCreateGlobalVector(rdm, val)); 8270 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8271 PetscCall(VecGetArray(*val, &v)); 8272 for (c = cStart; c < cEnd; ++c) { 8273 PetscScalar *lv; 8274 PetscInt cval; 8275 8276 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8277 PetscCall(DMLabelGetValue(label, c, &cval)); 8278 *lv = cval; 8279 } 8280 PetscCall(VecRestoreArray(*val, &v)); 8281 PetscCall(DMDestroy(&rdm)); 8282 PetscFunctionReturn(0); 8283 } 8284 8285 /*@ 8286 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8287 8288 Input Parameter: 8289 . dm - The DMPlex object 8290 8291 Notes: 8292 This is a useful diagnostic when creating meshes programmatically. 8293 8294 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8295 8296 Level: developer 8297 8298 .seealso: `DMCreate()`, `DMSetFromOptions()` 8299 @*/ 8300 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8301 { 8302 PetscSection coneSection, supportSection; 8303 const PetscInt *cone, *support; 8304 PetscInt coneSize, c, supportSize, s; 8305 PetscInt pStart, pEnd, p, pp, csize, ssize; 8306 PetscBool storagecheck = PETSC_TRUE; 8307 8308 PetscFunctionBegin; 8309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8310 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8311 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8312 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8313 /* Check that point p is found in the support of its cone points, and vice versa */ 8314 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8315 for (p = pStart; p < pEnd; ++p) { 8316 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8317 PetscCall(DMPlexGetCone(dm, p, &cone)); 8318 for (c = 0; c < coneSize; ++c) { 8319 PetscBool dup = PETSC_FALSE; 8320 PetscInt d; 8321 for (d = c-1; d >= 0; --d) { 8322 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8323 } 8324 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8325 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8326 for (s = 0; s < supportSize; ++s) { 8327 if (support[s] == p) break; 8328 } 8329 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8331 for (s = 0; s < coneSize; ++s) { 8332 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8333 } 8334 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8335 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8336 for (s = 0; s < supportSize; ++s) { 8337 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8338 } 8339 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8340 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]); 8341 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8342 } 8343 } 8344 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8345 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8346 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8347 PetscCall(DMPlexGetSupport(dm, p, &support)); 8348 for (s = 0; s < supportSize; ++s) { 8349 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8350 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8351 for (c = 0; c < coneSize; ++c) { 8352 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8353 if (cone[c] != pp) { c = 0; break; } 8354 if (cone[c] == p) break; 8355 } 8356 if (c >= coneSize) { 8357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8358 for (c = 0; c < supportSize; ++c) { 8359 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8360 } 8361 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8362 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8363 for (c = 0; c < coneSize; ++c) { 8364 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8365 } 8366 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8367 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8368 } 8369 } 8370 } 8371 if (storagecheck) { 8372 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8373 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8374 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8375 } 8376 PetscFunctionReturn(0); 8377 } 8378 8379 /* 8380 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. 8381 */ 8382 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8383 { 8384 DMPolytopeType cct; 8385 PetscInt ptpoints[4]; 8386 const PetscInt *cone, *ccone, *ptcone; 8387 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8388 8389 PetscFunctionBegin; 8390 *unsplit = 0; 8391 switch (ct) { 8392 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8393 ptpoints[npt++] = c; 8394 break; 8395 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8396 PetscCall(DMPlexGetCone(dm, c, &cone)); 8397 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8398 for (cp = 0; cp < coneSize; ++cp) { 8399 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8400 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8401 } 8402 break; 8403 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8404 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8405 PetscCall(DMPlexGetCone(dm, c, &cone)); 8406 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8407 for (cp = 0; cp < coneSize; ++cp) { 8408 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8409 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8410 for (ccp = 0; ccp < cconeSize; ++ccp) { 8411 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8412 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8413 PetscInt p; 8414 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8415 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8416 } 8417 } 8418 } 8419 break; 8420 default: break; 8421 } 8422 for (pt = 0; pt < npt; ++pt) { 8423 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8424 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8425 } 8426 PetscFunctionReturn(0); 8427 } 8428 8429 /*@ 8430 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8431 8432 Input Parameters: 8433 + dm - The DMPlex object 8434 - cellHeight - Normally 0 8435 8436 Notes: 8437 This is a useful diagnostic when creating meshes programmatically. 8438 Currently applicable only to homogeneous simplex or tensor meshes. 8439 8440 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8441 8442 Level: developer 8443 8444 .seealso: `DMCreate()`, `DMSetFromOptions()` 8445 @*/ 8446 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8447 { 8448 DMPlexInterpolatedFlag interp; 8449 DMPolytopeType ct; 8450 PetscInt vStart, vEnd, cStart, cEnd, c; 8451 8452 PetscFunctionBegin; 8453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8454 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8455 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8456 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8457 for (c = cStart; c < cEnd; ++c) { 8458 PetscInt *closure = NULL; 8459 PetscInt coneSize, closureSize, cl, Nv = 0; 8460 8461 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8462 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8463 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8464 if (interp == DMPLEX_INTERPOLATED_FULL) { 8465 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8466 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)); 8467 } 8468 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8469 for (cl = 0; cl < closureSize*2; cl += 2) { 8470 const PetscInt p = closure[cl]; 8471 if ((p >= vStart) && (p < vEnd)) ++Nv; 8472 } 8473 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8474 /* Special Case: Tensor faces with identified vertices */ 8475 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8476 PetscInt unsplit; 8477 8478 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8479 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8480 } 8481 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)); 8482 } 8483 PetscFunctionReturn(0); 8484 } 8485 8486 /*@ 8487 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8488 8489 Collective 8490 8491 Input Parameters: 8492 + dm - The DMPlex object 8493 - cellHeight - Normally 0 8494 8495 Notes: 8496 This is a useful diagnostic when creating meshes programmatically. 8497 This routine is only relevant for meshes that are fully interpolated across all ranks. 8498 It will error out if a partially interpolated mesh is given on some rank. 8499 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8500 8501 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8502 8503 Level: developer 8504 8505 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8506 @*/ 8507 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8508 { 8509 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8510 DMPlexInterpolatedFlag interpEnum; 8511 8512 PetscFunctionBegin; 8513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8514 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8515 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8516 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8517 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8518 PetscFunctionReturn(0); 8519 } 8520 8521 PetscCall(DMGetDimension(dm, &dim)); 8522 PetscCall(DMPlexGetDepth(dm, &depth)); 8523 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8524 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8525 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8526 for (c = cStart; c < cEnd; ++c) { 8527 const PetscInt *cone, *ornt, *faceSizes, *faces; 8528 const DMPolytopeType *faceTypes; 8529 DMPolytopeType ct; 8530 PetscInt numFaces, coneSize, f; 8531 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8532 8533 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8534 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8535 if (unsplit) continue; 8536 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8537 PetscCall(DMPlexGetCone(dm, c, &cone)); 8538 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8539 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8540 for (cl = 0; cl < closureSize*2; cl += 2) { 8541 const PetscInt p = closure[cl]; 8542 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8543 } 8544 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8545 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); 8546 for (f = 0; f < numFaces; ++f) { 8547 DMPolytopeType fct; 8548 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8549 8550 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8551 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8552 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8553 const PetscInt p = fclosure[cl]; 8554 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8555 } 8556 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]); 8557 for (v = 0; v < fnumCorners; ++v) { 8558 if (fclosure[v] != faces[fOff+v]) { 8559 PetscInt v1; 8560 8561 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8562 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8563 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8564 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8565 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8566 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]); 8567 } 8568 } 8569 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8570 fOff += faceSizes[f]; 8571 } 8572 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8573 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8574 } 8575 } 8576 PetscFunctionReturn(0); 8577 } 8578 8579 /*@ 8580 DMPlexCheckGeometry - Check the geometry of mesh cells 8581 8582 Input Parameter: 8583 . dm - The DMPlex object 8584 8585 Notes: 8586 This is a useful diagnostic when creating meshes programmatically. 8587 8588 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8589 8590 Level: developer 8591 8592 .seealso: `DMCreate()`, `DMSetFromOptions()` 8593 @*/ 8594 PetscErrorCode DMPlexCheckGeometry(DM dm) 8595 { 8596 Vec coordinates; 8597 PetscReal detJ, J[9], refVol = 1.0; 8598 PetscReal vol; 8599 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8600 8601 PetscFunctionBegin; 8602 PetscCall(DMGetDimension(dm, &dim)); 8603 PetscCall(DMGetCoordinateDim(dm, &dE)); 8604 if (dim != dE) PetscFunctionReturn(0); 8605 PetscCall(DMPlexGetDepth(dm, &depth)); 8606 for (d = 0; d < dim; ++d) refVol *= 2.0; 8607 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8608 /* Make sure local coordinates are created, because that step is collective */ 8609 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8610 for (c = cStart; c < cEnd; ++c) { 8611 DMPolytopeType ct; 8612 PetscInt unsplit; 8613 PetscBool ignoreZeroVol = PETSC_FALSE; 8614 8615 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8616 switch (ct) { 8617 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8618 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8619 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8620 ignoreZeroVol = PETSC_TRUE; break; 8621 default: break; 8622 } 8623 switch (ct) { 8624 case DM_POLYTOPE_TRI_PRISM: 8625 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8626 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8627 case DM_POLYTOPE_PYRAMID: 8628 continue; 8629 default: break; 8630 } 8631 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8632 if (unsplit) continue; 8633 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8634 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); 8635 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8636 /* This should work with periodicity since DG coordinates should be used */ 8637 if (depth > 1) { 8638 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8639 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); 8640 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8641 } 8642 } 8643 PetscFunctionReturn(0); 8644 } 8645 8646 /*@ 8647 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8648 8649 Collective 8650 8651 Input Parameters: 8652 + dm - The DMPlex object 8653 - pointSF - The Point SF, or NULL for Point SF attached to DM 8654 8655 Notes: 8656 This is mainly intended for debugging/testing purposes. 8657 8658 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8659 8660 Level: developer 8661 8662 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8663 @*/ 8664 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8665 { 8666 PetscInt l, nleaves, nroots, overlap; 8667 const PetscInt *locals; 8668 const PetscSFNode *remotes; 8669 PetscBool distributed; 8670 MPI_Comm comm; 8671 PetscMPIInt rank; 8672 8673 PetscFunctionBegin; 8674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8675 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8676 else pointSF = dm->sf; 8677 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8678 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8679 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8680 { 8681 PetscMPIInt mpiFlag; 8682 8683 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8684 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8685 } 8686 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8687 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8688 if (!distributed) { 8689 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); 8690 PetscFunctionReturn(0); 8691 } 8692 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); 8693 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8694 8695 /* Check SF graph is compatible with DMPlex chart */ 8696 { 8697 PetscInt pStart, pEnd, maxLeaf; 8698 8699 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8700 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8701 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8702 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8703 } 8704 8705 /* Check Point SF has no local points referenced */ 8706 for (l = 0; l < nleaves; l++) { 8707 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); 8708 } 8709 8710 /* Check there are no cells in interface */ 8711 if (!overlap) { 8712 PetscInt cellHeight, cStart, cEnd; 8713 8714 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8715 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8716 for (l = 0; l < nleaves; ++l) { 8717 const PetscInt point = locals ? locals[l] : l; 8718 8719 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8720 } 8721 } 8722 8723 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8724 { 8725 const PetscInt *rootdegree; 8726 8727 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8728 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8729 for (l = 0; l < nleaves; ++l) { 8730 const PetscInt point = locals ? locals[l] : l; 8731 const PetscInt *cone; 8732 PetscInt coneSize, c, idx; 8733 8734 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8735 PetscCall(DMPlexGetCone(dm, point, &cone)); 8736 for (c = 0; c < coneSize; ++c) { 8737 if (!rootdegree[cone[c]]) { 8738 if (locals) { 8739 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8740 } else { 8741 idx = (cone[c] < nleaves) ? cone[c] : -1; 8742 } 8743 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8744 } 8745 } 8746 } 8747 } 8748 PetscFunctionReturn(0); 8749 } 8750 8751 /*@ 8752 DMPlexCheck - Perform various checks of Plex sanity 8753 8754 Input Parameter: 8755 . dm - The DMPlex object 8756 8757 Notes: 8758 This is a useful diagnostic when creating meshes programmatically. 8759 8760 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8761 8762 Currently does not include DMPlexCheckCellShape(). 8763 8764 Level: developer 8765 8766 .seealso: DMCreate(), DMSetFromOptions() 8767 @*/ 8768 PetscErrorCode DMPlexCheck(DM dm) 8769 { 8770 PetscInt cellHeight; 8771 8772 PetscFunctionBegin; 8773 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8774 PetscCall(DMPlexCheckSymmetry(dm)); 8775 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8776 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8777 PetscCall(DMPlexCheckGeometry(dm)); 8778 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8779 PetscCall(DMPlexCheckInterfaceCones(dm)); 8780 PetscFunctionReturn(0); 8781 } 8782 8783 typedef struct cell_stats 8784 { 8785 PetscReal min, max, sum, squaresum; 8786 PetscInt count; 8787 } cell_stats_t; 8788 8789 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8790 { 8791 PetscInt i, N = *len; 8792 8793 for (i = 0; i < N; i++) { 8794 cell_stats_t *A = (cell_stats_t *) a; 8795 cell_stats_t *B = (cell_stats_t *) b; 8796 8797 B->min = PetscMin(A->min,B->min); 8798 B->max = PetscMax(A->max,B->max); 8799 B->sum += A->sum; 8800 B->squaresum += A->squaresum; 8801 B->count += A->count; 8802 } 8803 } 8804 8805 /*@ 8806 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8807 8808 Collective on dm 8809 8810 Input Parameters: 8811 + dm - The DMPlex object 8812 . output - If true, statistics will be displayed on stdout 8813 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8814 8815 Notes: 8816 This is mainly intended for debugging/testing purposes. 8817 8818 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8819 8820 Level: developer 8821 8822 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8823 @*/ 8824 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8825 { 8826 DM dmCoarse; 8827 cell_stats_t stats, globalStats; 8828 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8829 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8830 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8831 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8832 PetscMPIInt rank,size; 8833 8834 PetscFunctionBegin; 8835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8836 stats.min = PETSC_MAX_REAL; 8837 stats.max = PETSC_MIN_REAL; 8838 stats.sum = stats.squaresum = 0.; 8839 stats.count = 0; 8840 8841 PetscCallMPI(MPI_Comm_size(comm, &size)); 8842 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8843 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8844 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8845 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8846 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8847 for (c = cStart; c < cEnd; c++) { 8848 PetscInt i; 8849 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8850 8851 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8852 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8853 for (i = 0; i < PetscSqr(cdim); ++i) { 8854 frobJ += J[i] * J[i]; 8855 frobInvJ += invJ[i] * invJ[i]; 8856 } 8857 cond2 = frobJ * frobInvJ; 8858 cond = PetscSqrtReal(cond2); 8859 8860 stats.min = PetscMin(stats.min,cond); 8861 stats.max = PetscMax(stats.max,cond); 8862 stats.sum += cond; 8863 stats.squaresum += cond2; 8864 stats.count++; 8865 if (output && cond > limit) { 8866 PetscSection coordSection; 8867 Vec coordsLocal; 8868 PetscScalar *coords = NULL; 8869 PetscInt Nv, d, clSize, cl, *closure = NULL; 8870 8871 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8872 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8873 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8874 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8875 for (i = 0; i < Nv/cdim; ++i) { 8876 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8877 for (d = 0; d < cdim; ++d) { 8878 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8879 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8880 } 8881 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8882 } 8883 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8884 for (cl = 0; cl < clSize*2; cl += 2) { 8885 const PetscInt edge = closure[cl]; 8886 8887 if ((edge >= eStart) && (edge < eEnd)) { 8888 PetscReal len; 8889 8890 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8891 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8892 } 8893 } 8894 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8895 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8896 } 8897 } 8898 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8899 8900 if (size > 1) { 8901 PetscMPIInt blockLengths[2] = {4,1}; 8902 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8903 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8904 MPI_Op statReduce; 8905 8906 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8907 PetscCallMPI(MPI_Type_commit(&statType)); 8908 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8909 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8910 PetscCallMPI(MPI_Op_free(&statReduce)); 8911 PetscCallMPI(MPI_Type_free(&statType)); 8912 } else { 8913 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8914 } 8915 if (rank == 0) { 8916 count = globalStats.count; 8917 min = globalStats.min; 8918 max = globalStats.max; 8919 mean = globalStats.sum / globalStats.count; 8920 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8921 } 8922 8923 if (output) { 8924 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)); 8925 } 8926 PetscCall(PetscFree2(J,invJ)); 8927 8928 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8929 if (dmCoarse) { 8930 PetscBool isplex; 8931 8932 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8933 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8934 } 8935 PetscFunctionReturn(0); 8936 } 8937 8938 /*@ 8939 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8940 orthogonal quality below given tolerance. 8941 8942 Collective on dm 8943 8944 Input Parameters: 8945 + dm - The DMPlex object 8946 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8947 - atol - [0, 1] Absolute tolerance for tagging cells. 8948 8949 Output Parameters: 8950 + OrthQual - Vec containing orthogonal quality per cell 8951 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8952 8953 Options Database Keys: 8954 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8955 supported. 8956 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8957 8958 Notes: 8959 Orthogonal quality is given by the following formula: 8960 8961 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8962 8963 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 8964 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8965 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8966 calculating the cosine of the angle between these vectors. 8967 8968 Orthogonal quality ranges from 1 (best) to 0 (worst). 8969 8970 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8971 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8972 8973 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8974 8975 Level: intermediate 8976 8977 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8978 @*/ 8979 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8980 { 8981 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8982 PetscInt *idx; 8983 PetscScalar *oqVals; 8984 const PetscScalar *cellGeomArr, *faceGeomArr; 8985 PetscReal *ci, *fi, *Ai; 8986 MPI_Comm comm; 8987 Vec cellgeom, facegeom; 8988 DM dmFace, dmCell; 8989 IS glob; 8990 ISLocalToGlobalMapping ltog; 8991 PetscViewer vwr; 8992 8993 PetscFunctionBegin; 8994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8995 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8996 PetscValidPointer(OrthQual, 4); 8997 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8998 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8999 PetscCall(DMGetDimension(dm, &nc)); 9000 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9001 { 9002 DMPlexInterpolatedFlag interpFlag; 9003 9004 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9005 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9006 PetscMPIInt rank; 9007 9008 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9009 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9010 } 9011 } 9012 if (OrthQualLabel) { 9013 PetscValidPointer(OrthQualLabel, 5); 9014 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9015 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9016 } else {*OrthQualLabel = NULL;} 9017 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9018 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9019 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9020 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9021 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9022 PetscCall(VecCreate(comm, OrthQual)); 9023 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9024 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9025 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9026 PetscCall(VecSetUp(*OrthQual)); 9027 PetscCall(ISDestroy(&glob)); 9028 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9029 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9030 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9031 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9032 PetscCall(VecGetDM(cellgeom, &dmCell)); 9033 PetscCall(VecGetDM(facegeom, &dmFace)); 9034 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9035 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9036 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9037 PetscInt cellarr[2], *adj = NULL; 9038 PetscScalar *cArr, *fArr; 9039 PetscReal minvalc = 1.0, minvalf = 1.0; 9040 PetscFVCellGeom *cg; 9041 9042 idx[cellIter] = cell-cStart; 9043 cellarr[0] = cell; 9044 /* Make indexing into cellGeom easier */ 9045 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9046 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9047 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9048 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9049 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9050 PetscInt i; 9051 const PetscInt neigh = adj[cellneigh]; 9052 PetscReal normci = 0, normfi = 0, normai = 0; 9053 PetscFVCellGeom *cgneigh; 9054 PetscFVFaceGeom *fg; 9055 9056 /* Don't count ourselves in the neighbor list */ 9057 if (neigh == cell) continue; 9058 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9059 cellarr[1] = neigh; 9060 { 9061 PetscInt numcovpts; 9062 const PetscInt *covpts; 9063 9064 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9065 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9066 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9067 } 9068 9069 /* Compute c_i, f_i and their norms */ 9070 for (i = 0; i < nc; i++) { 9071 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9072 fi[i] = fg->centroid[i] - cg->centroid[i]; 9073 Ai[i] = fg->normal[i]; 9074 normci += PetscPowReal(ci[i], 2); 9075 normfi += PetscPowReal(fi[i], 2); 9076 normai += PetscPowReal(Ai[i], 2); 9077 } 9078 normci = PetscSqrtReal(normci); 9079 normfi = PetscSqrtReal(normfi); 9080 normai = PetscSqrtReal(normai); 9081 9082 /* Normalize and compute for each face-cell-normal pair */ 9083 for (i = 0; i < nc; i++) { 9084 ci[i] = ci[i]/normci; 9085 fi[i] = fi[i]/normfi; 9086 Ai[i] = Ai[i]/normai; 9087 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9088 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9089 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9090 } 9091 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9092 minvalc = PetscRealPart(cArr[cellneighiter]); 9093 } 9094 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9095 minvalf = PetscRealPart(fArr[cellneighiter]); 9096 } 9097 } 9098 PetscCall(PetscFree(adj)); 9099 PetscCall(PetscFree2(cArr, fArr)); 9100 /* Defer to cell if they're equal */ 9101 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9102 if (OrthQualLabel) { 9103 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9104 } 9105 } 9106 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9107 PetscCall(VecAssemblyBegin(*OrthQual)); 9108 PetscCall(VecAssemblyEnd(*OrthQual)); 9109 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9110 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9111 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9112 if (OrthQualLabel) { 9113 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9114 } 9115 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9116 PetscCall(PetscViewerDestroy(&vwr)); 9117 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9118 PetscFunctionReturn(0); 9119 } 9120 9121 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9122 * interpolator construction */ 9123 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9124 { 9125 PetscSection section, newSection, gsection; 9126 PetscSF sf; 9127 PetscBool hasConstraints, ghasConstraints; 9128 9129 PetscFunctionBegin; 9130 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9131 PetscValidPointer(odm,2); 9132 PetscCall(DMGetLocalSection(dm, §ion)); 9133 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9134 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9135 if (!ghasConstraints) { 9136 PetscCall(PetscObjectReference((PetscObject)dm)); 9137 *odm = dm; 9138 PetscFunctionReturn(0); 9139 } 9140 PetscCall(DMClone(dm, odm)); 9141 PetscCall(DMCopyFields(dm, *odm)); 9142 PetscCall(DMGetLocalSection(*odm, &newSection)); 9143 PetscCall(DMGetPointSF(*odm, &sf)); 9144 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9145 PetscCall(DMSetGlobalSection(*odm, gsection)); 9146 PetscCall(PetscSectionDestroy(&gsection)); 9147 PetscFunctionReturn(0); 9148 } 9149 9150 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9151 { 9152 DM dmco, dmfo; 9153 Mat interpo; 9154 Vec rscale; 9155 Vec cglobalo, clocal; 9156 Vec fglobal, fglobalo, flocal; 9157 PetscBool regular; 9158 9159 PetscFunctionBegin; 9160 PetscCall(DMGetFullDM(dmc, &dmco)); 9161 PetscCall(DMGetFullDM(dmf, &dmfo)); 9162 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9163 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9164 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9165 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9166 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9167 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9168 PetscCall(VecSet(cglobalo, 0.)); 9169 PetscCall(VecSet(clocal, 0.)); 9170 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9171 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9172 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9173 PetscCall(VecSet(fglobal, 0.)); 9174 PetscCall(VecSet(fglobalo, 0.)); 9175 PetscCall(VecSet(flocal, 0.)); 9176 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9177 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9178 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9179 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9180 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9181 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9182 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9183 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9184 *shift = fglobal; 9185 PetscCall(VecDestroy(&flocal)); 9186 PetscCall(VecDestroy(&fglobalo)); 9187 PetscCall(VecDestroy(&clocal)); 9188 PetscCall(VecDestroy(&cglobalo)); 9189 PetscCall(VecDestroy(&rscale)); 9190 PetscCall(MatDestroy(&interpo)); 9191 PetscCall(DMDestroy(&dmfo)); 9192 PetscCall(DMDestroy(&dmco)); 9193 PetscFunctionReturn(0); 9194 } 9195 9196 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9197 { 9198 PetscObject shifto; 9199 Vec shift; 9200 9201 PetscFunctionBegin; 9202 if (!interp) { 9203 Vec rscale; 9204 9205 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9206 PetscCall(VecDestroy(&rscale)); 9207 } else { 9208 PetscCall(PetscObjectReference((PetscObject)interp)); 9209 } 9210 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9211 if (!shifto) { 9212 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9213 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9214 shifto = (PetscObject) shift; 9215 PetscCall(VecDestroy(&shift)); 9216 } 9217 shift = (Vec) shifto; 9218 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9219 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9220 PetscCall(MatDestroy(&interp)); 9221 PetscFunctionReturn(0); 9222 } 9223 9224 /* Pointwise interpolation 9225 Just code FEM for now 9226 u^f = I u^c 9227 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9228 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9229 I_{ij} = psi^f_i phi^c_j 9230 */ 9231 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9232 { 9233 PetscSection gsc, gsf; 9234 PetscInt m, n; 9235 void *ctx; 9236 DM cdm; 9237 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9238 9239 PetscFunctionBegin; 9240 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9241 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9242 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9243 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9244 9245 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9246 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9247 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9248 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9249 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9250 9251 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9252 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9253 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9254 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9255 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9256 if (scaling) { 9257 /* Use naive scaling */ 9258 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9259 } 9260 PetscFunctionReturn(0); 9261 } 9262 9263 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9264 { 9265 VecScatter ctx; 9266 9267 PetscFunctionBegin; 9268 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9269 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9270 PetscCall(VecScatterDestroy(&ctx)); 9271 PetscFunctionReturn(0); 9272 } 9273 9274 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9275 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9276 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9277 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9278 { 9279 const PetscInt Nc = uOff[1] - uOff[0]; 9280 PetscInt c; 9281 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9282 } 9283 9284 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9285 { 9286 DM dmc; 9287 PetscDS ds; 9288 Vec ones, locmass; 9289 IS cellIS; 9290 PetscFormKey key; 9291 PetscInt depth; 9292 9293 PetscFunctionBegin; 9294 PetscCall(DMClone(dm, &dmc)); 9295 PetscCall(DMCopyDisc(dm, dmc)); 9296 PetscCall(DMGetDS(dmc, &ds)); 9297 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9298 PetscCall(DMCreateGlobalVector(dmc, mass)); 9299 PetscCall(DMGetLocalVector(dmc, &ones)); 9300 PetscCall(DMGetLocalVector(dmc, &locmass)); 9301 PetscCall(DMPlexGetDepth(dmc, &depth)); 9302 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9303 PetscCall(VecSet(locmass, 0.0)); 9304 PetscCall(VecSet(ones, 1.0)); 9305 key.label = NULL; 9306 key.value = 0; 9307 key.field = 0; 9308 key.part = 0; 9309 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9310 PetscCall(ISDestroy(&cellIS)); 9311 PetscCall(VecSet(*mass, 0.0)); 9312 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9313 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9314 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9315 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9316 PetscCall(DMDestroy(&dmc)); 9317 PetscFunctionReturn(0); 9318 } 9319 9320 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9321 { 9322 PetscSection gsc, gsf; 9323 PetscInt m, n; 9324 void *ctx; 9325 DM cdm; 9326 PetscBool regular; 9327 9328 PetscFunctionBegin; 9329 if (dmFine == dmCoarse) { 9330 DM dmc; 9331 PetscDS ds; 9332 PetscWeakForm wf; 9333 Vec u; 9334 IS cellIS; 9335 PetscFormKey key; 9336 PetscInt depth; 9337 9338 PetscCall(DMClone(dmFine, &dmc)); 9339 PetscCall(DMCopyDisc(dmFine, dmc)); 9340 PetscCall(DMGetDS(dmc, &ds)); 9341 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9342 PetscCall(PetscWeakFormClear(wf)); 9343 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9344 PetscCall(DMCreateMatrix(dmc, mass)); 9345 PetscCall(DMGetGlobalVector(dmc, &u)); 9346 PetscCall(DMPlexGetDepth(dmc, &depth)); 9347 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9348 PetscCall(MatZeroEntries(*mass)); 9349 key.label = NULL; 9350 key.value = 0; 9351 key.field = 0; 9352 key.part = 0; 9353 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9354 PetscCall(ISDestroy(&cellIS)); 9355 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9356 PetscCall(DMDestroy(&dmc)); 9357 } else { 9358 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9359 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9360 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9361 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9362 9363 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9364 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9365 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9366 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9367 9368 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9369 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9370 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9371 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9372 } 9373 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9374 PetscFunctionReturn(0); 9375 } 9376 9377 /*@ 9378 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9379 9380 Input Parameter: 9381 . dm - The DMPlex object 9382 9383 Output Parameter: 9384 . regular - The flag 9385 9386 Level: intermediate 9387 9388 .seealso: `DMPlexSetRegularRefinement()` 9389 @*/ 9390 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9391 { 9392 PetscFunctionBegin; 9393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9394 PetscValidBoolPointer(regular, 2); 9395 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9396 PetscFunctionReturn(0); 9397 } 9398 9399 /*@ 9400 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9401 9402 Input Parameters: 9403 + dm - The DMPlex object 9404 - regular - The flag 9405 9406 Level: intermediate 9407 9408 .seealso: `DMPlexGetRegularRefinement()` 9409 @*/ 9410 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9411 { 9412 PetscFunctionBegin; 9413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9414 ((DM_Plex *) dm->data)->regularRefinement = regular; 9415 PetscFunctionReturn(0); 9416 } 9417 9418 /* anchors */ 9419 /*@ 9420 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9421 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9422 9423 not collective 9424 9425 Input Parameter: 9426 . dm - The DMPlex object 9427 9428 Output Parameters: 9429 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9430 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9431 9432 Level: intermediate 9433 9434 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9435 @*/ 9436 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9437 { 9438 DM_Plex *plex = (DM_Plex *)dm->data; 9439 9440 PetscFunctionBegin; 9441 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9442 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9443 if (anchorSection) *anchorSection = plex->anchorSection; 9444 if (anchorIS) *anchorIS = plex->anchorIS; 9445 PetscFunctionReturn(0); 9446 } 9447 9448 /*@ 9449 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9450 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9451 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9452 9453 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9454 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9455 9456 collective on dm 9457 9458 Input Parameters: 9459 + dm - The DMPlex object 9460 . 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). 9461 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9462 9463 The reference counts of anchorSection and anchorIS are incremented. 9464 9465 Level: intermediate 9466 9467 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9468 @*/ 9469 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9470 { 9471 DM_Plex *plex = (DM_Plex *)dm->data; 9472 PetscMPIInt result; 9473 9474 PetscFunctionBegin; 9475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9476 if (anchorSection) { 9477 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9478 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9479 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9480 } 9481 if (anchorIS) { 9482 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9483 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9484 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9485 } 9486 9487 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9488 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9489 plex->anchorSection = anchorSection; 9490 9491 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9492 PetscCall(ISDestroy(&plex->anchorIS)); 9493 plex->anchorIS = anchorIS; 9494 9495 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9496 PetscInt size, a, pStart, pEnd; 9497 const PetscInt *anchors; 9498 9499 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9500 PetscCall(ISGetLocalSize(anchorIS,&size)); 9501 PetscCall(ISGetIndices(anchorIS,&anchors)); 9502 for (a = 0; a < size; a++) { 9503 PetscInt p; 9504 9505 p = anchors[a]; 9506 if (p >= pStart && p < pEnd) { 9507 PetscInt dof; 9508 9509 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9510 if (dof) { 9511 9512 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9513 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9514 } 9515 } 9516 } 9517 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9518 } 9519 /* reset the generic constraints */ 9520 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9521 PetscFunctionReturn(0); 9522 } 9523 9524 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9525 { 9526 PetscSection anchorSection; 9527 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9528 9529 PetscFunctionBegin; 9530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9531 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9532 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9533 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9534 if (numFields) { 9535 PetscInt f; 9536 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9537 9538 for (f = 0; f < numFields; f++) { 9539 PetscInt numComp; 9540 9541 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9542 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9543 } 9544 } 9545 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9546 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9547 pStart = PetscMax(pStart,sStart); 9548 pEnd = PetscMin(pEnd,sEnd); 9549 pEnd = PetscMax(pStart,pEnd); 9550 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9551 for (p = pStart; p < pEnd; p++) { 9552 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9553 if (dof) { 9554 PetscCall(PetscSectionGetDof(section,p,&dof)); 9555 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9556 for (f = 0; f < numFields; f++) { 9557 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9558 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9559 } 9560 } 9561 } 9562 PetscCall(PetscSectionSetUp(*cSec)); 9563 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9564 PetscFunctionReturn(0); 9565 } 9566 9567 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9568 { 9569 PetscSection aSec; 9570 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9571 const PetscInt *anchors; 9572 PetscInt numFields, f; 9573 IS aIS; 9574 MatType mtype; 9575 PetscBool iscuda,iskokkos; 9576 9577 PetscFunctionBegin; 9578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9579 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9580 PetscCall(PetscSectionGetStorageSize(section, &n)); 9581 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9582 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9583 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9584 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9585 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9586 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9587 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9588 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9589 else mtype = MATSEQAIJ; 9590 PetscCall(MatSetType(*cMat,mtype)); 9591 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9592 PetscCall(ISGetIndices(aIS,&anchors)); 9593 /* cSec will be a subset of aSec and section */ 9594 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9595 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9596 PetscCall(PetscMalloc1(m+1,&i)); 9597 i[0] = 0; 9598 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9599 for (p = pStart; p < pEnd; p++) { 9600 PetscInt rDof, rOff, r; 9601 9602 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9603 if (!rDof) continue; 9604 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9605 if (numFields) { 9606 for (f = 0; f < numFields; f++) { 9607 annz = 0; 9608 for (r = 0; r < rDof; r++) { 9609 a = anchors[rOff + r]; 9610 if (a < sStart || a >= sEnd) continue; 9611 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9612 annz += aDof; 9613 } 9614 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9615 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9616 for (q = 0; q < dof; q++) { 9617 i[off + q + 1] = i[off + q] + annz; 9618 } 9619 } 9620 } else { 9621 annz = 0; 9622 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9623 for (q = 0; q < dof; q++) { 9624 a = anchors[rOff + q]; 9625 if (a < sStart || a >= sEnd) continue; 9626 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9627 annz += aDof; 9628 } 9629 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9630 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9631 for (q = 0; q < dof; q++) { 9632 i[off + q + 1] = i[off + q] + annz; 9633 } 9634 } 9635 } 9636 nnz = i[m]; 9637 PetscCall(PetscMalloc1(nnz,&j)); 9638 offset = 0; 9639 for (p = pStart; p < pEnd; p++) { 9640 if (numFields) { 9641 for (f = 0; f < numFields; f++) { 9642 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9643 for (q = 0; q < dof; q++) { 9644 PetscInt rDof, rOff, r; 9645 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9646 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9647 for (r = 0; r < rDof; r++) { 9648 PetscInt s; 9649 9650 a = anchors[rOff + r]; 9651 if (a < sStart || a >= sEnd) continue; 9652 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9653 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9654 for (s = 0; s < aDof; s++) { 9655 j[offset++] = aOff + s; 9656 } 9657 } 9658 } 9659 } 9660 } else { 9661 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9662 for (q = 0; q < dof; q++) { 9663 PetscInt rDof, rOff, r; 9664 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9665 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9666 for (r = 0; r < rDof; r++) { 9667 PetscInt s; 9668 9669 a = anchors[rOff + r]; 9670 if (a < sStart || a >= sEnd) continue; 9671 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9672 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9673 for (s = 0; s < aDof; s++) { 9674 j[offset++] = aOff + s; 9675 } 9676 } 9677 } 9678 } 9679 } 9680 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9681 PetscCall(PetscFree(i)); 9682 PetscCall(PetscFree(j)); 9683 PetscCall(ISRestoreIndices(aIS,&anchors)); 9684 PetscFunctionReturn(0); 9685 } 9686 9687 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9688 { 9689 DM_Plex *plex = (DM_Plex *)dm->data; 9690 PetscSection anchorSection, section, cSec; 9691 Mat cMat; 9692 9693 PetscFunctionBegin; 9694 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9695 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9696 if (anchorSection) { 9697 PetscInt Nf; 9698 9699 PetscCall(DMGetLocalSection(dm,§ion)); 9700 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9701 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9702 PetscCall(DMGetNumFields(dm,&Nf)); 9703 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9704 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9705 PetscCall(PetscSectionDestroy(&cSec)); 9706 PetscCall(MatDestroy(&cMat)); 9707 } 9708 PetscFunctionReturn(0); 9709 } 9710 9711 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9712 { 9713 IS subis; 9714 PetscSection section, subsection; 9715 9716 PetscFunctionBegin; 9717 PetscCall(DMGetLocalSection(dm, §ion)); 9718 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9719 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9720 /* Create subdomain */ 9721 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9722 /* Create submodel */ 9723 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9724 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9725 PetscCall(DMSetLocalSection(*subdm, subsection)); 9726 PetscCall(PetscSectionDestroy(&subsection)); 9727 PetscCall(DMCopyDisc(dm, *subdm)); 9728 /* Create map from submodel to global model */ 9729 if (is) { 9730 PetscSection sectionGlobal, subsectionGlobal; 9731 IS spIS; 9732 const PetscInt *spmap; 9733 PetscInt *subIndices; 9734 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9735 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9736 9737 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9738 PetscCall(ISGetIndices(spIS, &spmap)); 9739 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9740 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9741 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9742 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9743 for (p = pStart; p < pEnd; ++p) { 9744 PetscInt gdof, pSubSize = 0; 9745 9746 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9747 if (gdof > 0) { 9748 for (f = 0; f < Nf; ++f) { 9749 PetscInt fdof, fcdof; 9750 9751 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9752 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9753 pSubSize += fdof-fcdof; 9754 } 9755 subSize += pSubSize; 9756 if (pSubSize) { 9757 if (bs < 0) { 9758 bs = pSubSize; 9759 } else if (bs != pSubSize) { 9760 /* Layout does not admit a pointwise block size */ 9761 bs = 1; 9762 } 9763 } 9764 } 9765 } 9766 /* Must have same blocksize on all procs (some might have no points) */ 9767 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9768 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9769 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9770 else {bs = bsMinMax[0];} 9771 PetscCall(PetscMalloc1(subSize, &subIndices)); 9772 for (p = pStart; p < pEnd; ++p) { 9773 PetscInt gdof, goff; 9774 9775 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9776 if (gdof > 0) { 9777 const PetscInt point = spmap[p]; 9778 9779 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9780 for (f = 0; f < Nf; ++f) { 9781 PetscInt fdof, fcdof, fc, f2, poff = 0; 9782 9783 /* Can get rid of this loop by storing field information in the global section */ 9784 for (f2 = 0; f2 < f; ++f2) { 9785 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9786 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9787 poff += fdof-fcdof; 9788 } 9789 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9790 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9791 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9792 subIndices[subOff] = goff+poff+fc; 9793 } 9794 } 9795 } 9796 } 9797 PetscCall(ISRestoreIndices(spIS, &spmap)); 9798 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9799 if (bs > 1) { 9800 /* We need to check that the block size does not come from non-contiguous fields */ 9801 PetscInt i, j, set = 1; 9802 for (i = 0; i < subSize; i += bs) { 9803 for (j = 0; j < bs; ++j) { 9804 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9805 } 9806 } 9807 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9808 } 9809 /* Attach nullspace */ 9810 for (f = 0; f < Nf; ++f) { 9811 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9812 if ((*subdm)->nullspaceConstructors[f]) break; 9813 } 9814 if (f < Nf) { 9815 MatNullSpace nullSpace; 9816 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9817 9818 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9819 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9820 } 9821 } 9822 PetscFunctionReturn(0); 9823 } 9824 9825 /*@ 9826 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9827 9828 Input Parameter: 9829 - dm - The DM 9830 9831 Level: developer 9832 9833 Options Database Keys: 9834 . -dm_plex_monitor_throughput - Activate the monitor 9835 9836 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9837 @*/ 9838 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9839 { 9840 #if defined(PETSC_USE_LOG) 9841 PetscStageLog stageLog; 9842 PetscLogEvent event; 9843 PetscLogStage stage; 9844 PetscEventPerfInfo eventInfo; 9845 PetscReal cellRate, flopRate; 9846 PetscInt cStart, cEnd, Nf, N; 9847 const char *name; 9848 #endif 9849 9850 PetscFunctionBegin; 9851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9852 #if defined(PETSC_USE_LOG) 9853 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9854 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9855 PetscCall(DMGetNumFields(dm, &Nf)); 9856 PetscCall(PetscLogGetStageLog(&stageLog)); 9857 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9858 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9859 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9860 N = (cEnd - cStart)*Nf*eventInfo.count; 9861 flopRate = eventInfo.flops/eventInfo.time; 9862 cellRate = N/eventInfo.time; 9863 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))); 9864 #else 9865 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9866 #endif 9867 PetscFunctionReturn(0); 9868 } 9869