1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph,DMPLEX_RebalRewriteSF,DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 42 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 43 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 44 PetscFunctionReturn(0); 45 } 46 47 /*@ 48 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 49 50 Input Parameters: 51 + dm - The DMPlex object 52 - height - The cell height in the Plex, 0 is the default 53 54 Output Parameters: 55 + cStart - The first "normal" cell 56 - cEnd - The upper bound on "normal"" cells 57 58 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 59 60 Level: developer 61 62 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 63 @*/ 64 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 65 { 66 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 67 PetscInt cS, cE, c; 68 69 PetscFunctionBegin; 70 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 71 for (c = cS; c < cE; ++c) { 72 DMPolytopeType cct; 73 74 PetscCall(DMPlexGetCellType(dm, c, &cct)); 75 if ((PetscInt) cct < 0) break; 76 switch (cct) { 77 case DM_POLYTOPE_POINT: 78 case DM_POLYTOPE_SEGMENT: 79 case DM_POLYTOPE_TRIANGLE: 80 case DM_POLYTOPE_QUADRILATERAL: 81 case DM_POLYTOPE_TETRAHEDRON: 82 case DM_POLYTOPE_HEXAHEDRON: 83 ct = cct; 84 break; 85 default: break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) break; 88 } 89 if (ct != DM_POLYTOPE_UNKNOWN) { 90 DMLabel ctLabel; 91 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 94 // Reset label for fast lookup 95 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 96 } 97 if (cStart) *cStart = cS; 98 if (cEnd) *cEnd = cE; 99 PetscFunctionReturn(0); 100 } 101 102 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 103 { 104 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 105 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 106 107 PetscFunctionBegin; 108 *ft = PETSC_VTK_INVALID; 109 PetscCall(DMGetCoordinateDim(dm, &cdim)); 110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 111 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 112 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 113 if (field >= 0) { 114 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 115 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 116 } else { 117 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 118 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 119 } 120 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 121 if (globalvcdof[0]) { 122 *sStart = vStart; 123 *sEnd = vEnd; 124 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 125 else *ft = PETSC_VTK_POINT_FIELD; 126 } else if (globalvcdof[1]) { 127 *sStart = cStart; 128 *sEnd = cEnd; 129 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 130 else *ft = PETSC_VTK_CELL_FIELD; 131 } else { 132 if (field >= 0) { 133 const char *fieldname; 134 135 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 136 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 137 } else { 138 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 139 } 140 } 141 PetscFunctionReturn(0); 142 } 143 144 /*@ 145 DMPlexVecView1D - Plot many 1D solutions on the same line graph 146 147 Collective on dm 148 149 Input Parameters: 150 + dm - The DMPlex 151 . n - The number of vectors 152 . u - The array of local vectors 153 - viewer - The Draw viewer 154 155 Level: advanced 156 157 .seealso: `VecViewFromOptions()`, `VecView()` 158 @*/ 159 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 160 { 161 PetscDS ds; 162 PetscDraw draw = NULL; 163 PetscDrawLG lg; 164 Vec coordinates; 165 const PetscScalar *coords, **sol; 166 PetscReal *vals; 167 PetscInt *Nc; 168 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 169 char **names; 170 171 PetscFunctionBegin; 172 PetscCall(DMGetDS(dm, &ds)); 173 PetscCall(PetscDSGetNumFields(ds, &Nf)); 174 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 175 PetscCall(PetscDSGetComponents(ds, &Nc)); 176 177 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 178 if (!draw) PetscFunctionReturn(0); 179 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 180 181 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 182 for (i = 0, l = 0; i < n; ++i) { 183 const char *vname; 184 185 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 186 for (f = 0; f < Nf; ++f) { 187 PetscObject disc; 188 const char *fname; 189 char tmpname[PETSC_MAX_PATH_LEN]; 190 191 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 192 /* TODO Create names for components */ 193 for (c = 0; c < Nc[f]; ++c, ++l) { 194 PetscCall(PetscObjectGetName(disc, &fname)); 195 PetscCall(PetscStrcpy(tmpname, vname)); 196 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 197 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 198 PetscCall(PetscStrallocpy(tmpname, &names[l])); 199 } 200 } 201 } 202 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 203 /* Just add P_1 support for now */ 204 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 205 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 206 PetscCall(VecGetArrayRead(coordinates, &coords)); 207 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 208 for (v = vStart; v < vEnd; ++v) { 209 PetscScalar *x, *svals; 210 211 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 212 for (i = 0; i < n; ++i) { 213 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 214 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 215 } 216 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 217 } 218 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 219 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 220 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 221 PetscCall(PetscFree3(sol, names, vals)); 222 223 PetscCall(PetscDrawLGDraw(lg)); 224 PetscCall(PetscDrawLGDestroy(&lg)); 225 PetscFunctionReturn(0); 226 } 227 228 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 229 { 230 DM dm; 231 232 PetscFunctionBegin; 233 PetscCall(VecGetDM(u, &dm)); 234 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 235 PetscFunctionReturn(0); 236 } 237 238 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 239 { 240 DM dm; 241 PetscSection s; 242 PetscDraw draw, popup; 243 DM cdm; 244 PetscSection coordSection; 245 Vec coordinates; 246 const PetscScalar *coords, *array; 247 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 248 PetscReal vbound[2], time; 249 PetscBool flg; 250 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 251 const char *name; 252 char title[PETSC_MAX_PATH_LEN]; 253 254 PetscFunctionBegin; 255 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 256 PetscCall(VecGetDM(v, &dm)); 257 PetscCall(DMGetCoordinateDim(dm, &dim)); 258 PetscCall(DMGetLocalSection(dm, &s)); 259 PetscCall(PetscSectionGetNumFields(s, &Nf)); 260 PetscCall(DMGetCoarsenLevel(dm, &level)); 261 PetscCall(DMGetCoordinateDM(dm, &cdm)); 262 PetscCall(DMGetLocalSection(cdm, &coordSection)); 263 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 264 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 265 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 266 267 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 268 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 269 270 PetscCall(VecGetLocalSize(coordinates, &N)); 271 PetscCall(VecGetArrayRead(coordinates, &coords)); 272 for (c = 0; c < N; c += dim) { 273 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 274 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 275 } 276 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 277 PetscCall(PetscDrawClear(draw)); 278 279 /* Could implement something like DMDASelectFields() */ 280 for (f = 0; f < Nf; ++f) { 281 DM fdm = dm; 282 Vec fv = v; 283 IS fis; 284 char prefix[PETSC_MAX_PATH_LEN]; 285 const char *fname; 286 287 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 288 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 289 290 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 291 else {prefix[0] = '\0';} 292 if (Nf > 1) { 293 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 294 PetscCall(VecGetSubVector(v, fis, &fv)); 295 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 296 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 297 } 298 for (comp = 0; comp < Nc; ++comp, ++w) { 299 PetscInt nmax = 2; 300 301 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 302 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 303 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 304 PetscCall(PetscDrawSetTitle(draw, title)); 305 306 /* TODO Get max and min only for this component */ 307 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 308 if (!flg) { 309 PetscCall(VecMin(fv, NULL, &vbound[0])); 310 PetscCall(VecMax(fv, NULL, &vbound[1])); 311 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 312 } 313 PetscCall(PetscDrawGetPopup(draw, &popup)); 314 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 315 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 316 317 PetscCall(VecGetArrayRead(fv, &array)); 318 for (c = cStart; c < cEnd; ++c) { 319 PetscScalar *coords = NULL, *a = NULL; 320 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 321 322 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 323 if (a) { 324 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 325 color[1] = color[2] = color[3] = color[0]; 326 } else { 327 PetscScalar *vals = NULL; 328 PetscInt numVals, va; 329 330 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 331 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 332 switch (numVals/Nc) { 333 case 3: /* P1 Triangle */ 334 case 4: /* P1 Quadrangle */ 335 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 336 break; 337 case 6: /* P2 Triangle */ 338 case 8: /* P2 Quadrangle */ 339 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 340 break; 341 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 342 } 343 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 344 } 345 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 346 switch (numCoords) { 347 case 6: 348 case 12: /* Localized triangle */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 break; 351 case 8: 352 case 16: /* Localized quadrilateral */ 353 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 354 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 355 break; 356 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 357 } 358 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 359 } 360 PetscCall(VecRestoreArrayRead(fv, &array)); 361 PetscCall(PetscDrawFlush(draw)); 362 PetscCall(PetscDrawPause(draw)); 363 PetscCall(PetscDrawSave(draw)); 364 } 365 if (Nf > 1) { 366 PetscCall(VecRestoreSubVector(v, fis, &fv)); 367 PetscCall(ISDestroy(&fis)); 368 PetscCall(DMDestroy(&fdm)); 369 } 370 } 371 PetscFunctionReturn(0); 372 } 373 374 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 375 { 376 DM dm; 377 PetscDraw draw; 378 PetscInt dim; 379 PetscBool isnull; 380 381 PetscFunctionBegin; 382 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 383 PetscCall(PetscDrawIsNull(draw, &isnull)); 384 if (isnull) PetscFunctionReturn(0); 385 386 PetscCall(VecGetDM(v, &dm)); 387 PetscCall(DMGetCoordinateDim(dm, &dim)); 388 switch (dim) { 389 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 390 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 391 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 397 { 398 DM dm; 399 Vec locv; 400 const char *name; 401 PetscSection section; 402 PetscInt pStart, pEnd; 403 PetscInt numFields; 404 PetscViewerVTKFieldType ft; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(v, &dm)); 408 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 409 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 410 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 411 PetscCall(VecCopy(v, locv)); 412 PetscCall(DMGetLocalSection(dm, §ion)); 413 PetscCall(PetscSectionGetNumFields(section, &numFields)); 414 if (!numFields) { 415 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 416 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 417 } else { 418 PetscInt f; 419 420 for (f = 0; f < numFields; f++) { 421 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 422 if (ft == PETSC_VTK_INVALID) continue; 423 PetscCall(PetscObjectReference((PetscObject)locv)); 424 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 425 } 426 PetscCall(VecDestroy(&locv)); 427 } 428 PetscFunctionReturn(0); 429 } 430 431 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 432 { 433 DM dm; 434 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 435 436 PetscFunctionBegin; 437 PetscCall(VecGetDM(v, &dm)); 438 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 439 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 440 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 441 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 442 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 443 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 444 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 445 PetscInt i,numFields; 446 PetscObject fe; 447 PetscBool fem = PETSC_FALSE; 448 Vec locv = v; 449 const char *name; 450 PetscInt step; 451 PetscReal time; 452 453 PetscCall(DMGetNumFields(dm, &numFields)); 454 for (i=0; i<numFields; i++) { 455 PetscCall(DMGetField(dm, i, NULL, &fe)); 456 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 457 } 458 if (fem) { 459 PetscObject isZero; 460 461 PetscCall(DMGetLocalVector(dm, &locv)); 462 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 463 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 464 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 465 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 466 PetscCall(VecCopy(v, locv)); 467 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 468 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 469 } 470 if (isvtk) { 471 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 472 } else if (ishdf5) { 473 #if defined(PETSC_HAVE_HDF5) 474 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 475 #else 476 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 477 #endif 478 } else if (isdraw) { 479 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 480 } else if (isglvis) { 481 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 482 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 483 PetscCall(VecView_GLVis(locv, viewer)); 484 } else if (iscgns) { 485 #if defined(PETSC_HAVE_CGNS) 486 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 487 #else 488 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 489 #endif 490 } 491 if (fem) { 492 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 493 PetscCall(DMRestoreLocalVector(dm, &locv)); 494 } 495 } else { 496 PetscBool isseq; 497 498 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 499 if (isseq) PetscCall(VecView_Seq(v, viewer)); 500 else PetscCall(VecView_MPI(v, viewer)); 501 } 502 PetscFunctionReturn(0); 503 } 504 505 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 506 { 507 DM dm; 508 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 509 510 PetscFunctionBegin; 511 PetscCall(VecGetDM(v, &dm)); 512 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 513 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 514 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 515 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 516 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 517 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 518 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 519 if (isvtk || isdraw || isglvis || iscgns) { 520 Vec locv; 521 PetscObject isZero; 522 const char *name; 523 524 PetscCall(DMGetLocalVector(dm, &locv)); 525 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 526 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 527 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 528 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 529 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 530 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 531 PetscCall(VecView_Plex_Local(locv, viewer)); 532 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 533 PetscCall(DMRestoreLocalVector(dm, &locv)); 534 } else if (ishdf5) { 535 #if defined(PETSC_HAVE_HDF5) 536 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 537 #else 538 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 539 #endif 540 } else if (isexodusii) { 541 #if defined(PETSC_HAVE_EXODUSII) 542 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 543 #else 544 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 545 #endif 546 } else { 547 PetscBool isseq; 548 549 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 550 if (isseq) PetscCall(VecView_Seq(v, viewer)); 551 else PetscCall(VecView_MPI(v, viewer)); 552 } 553 PetscFunctionReturn(0); 554 } 555 556 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 557 { 558 DM dm; 559 MPI_Comm comm; 560 PetscViewerFormat format; 561 Vec v; 562 PetscBool isvtk, ishdf5; 563 564 PetscFunctionBegin; 565 PetscCall(VecGetDM(originalv, &dm)); 566 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 567 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 568 PetscCall(PetscViewerGetFormat(viewer, &format)); 569 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 570 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 571 if (format == PETSC_VIEWER_NATIVE) { 572 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 573 /* this need a better fix */ 574 if (dm->useNatural) { 575 if (dm->sfNatural) { 576 const char *vecname; 577 PetscInt n, nroots; 578 579 PetscCall(VecGetLocalSize(originalv, &n)); 580 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 581 if (n == nroots) { 582 PetscCall(DMGetGlobalVector(dm, &v)); 583 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 584 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 585 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 586 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 587 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 588 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 589 } else v = originalv; 590 } else v = originalv; 591 592 if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 595 #else 596 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isvtk) { 599 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 600 } else { 601 PetscBool isseq; 602 603 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 604 if (isseq) PetscCall(VecView_Seq(v, viewer)); 605 else PetscCall(VecView_MPI(v, viewer)); 606 } 607 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 608 PetscFunctionReturn(0); 609 } 610 611 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 612 { 613 DM dm; 614 PetscBool ishdf5; 615 616 PetscFunctionBegin; 617 PetscCall(VecGetDM(v, &dm)); 618 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 619 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 620 if (ishdf5) { 621 DM dmBC; 622 Vec gv; 623 const char *name; 624 625 PetscCall(DMGetOutputDM(dm, &dmBC)); 626 PetscCall(DMGetGlobalVector(dmBC, &gv)); 627 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 628 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 629 PetscCall(VecLoad_Default(gv, viewer)); 630 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 631 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 632 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 633 } else PetscCall(VecLoad_Default(v, viewer)); 634 PetscFunctionReturn(0); 635 } 636 637 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 638 { 639 DM dm; 640 PetscBool ishdf5,isexodusii; 641 642 PetscFunctionBegin; 643 PetscCall(VecGetDM(v, &dm)); 644 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 645 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 646 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 647 if (ishdf5) { 648 #if defined(PETSC_HAVE_HDF5) 649 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 650 #else 651 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 652 #endif 653 } else if (isexodusii) { 654 #if defined(PETSC_HAVE_EXODUSII) 655 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 658 #endif 659 } else PetscCall(VecLoad_Default(v, viewer)); 660 PetscFunctionReturn(0); 661 } 662 663 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 664 { 665 DM dm; 666 PetscViewerFormat format; 667 PetscBool ishdf5; 668 669 PetscFunctionBegin; 670 PetscCall(VecGetDM(originalv, &dm)); 671 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 672 PetscCall(PetscViewerGetFormat(viewer, &format)); 673 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 674 if (format == PETSC_VIEWER_NATIVE) { 675 if (dm->useNatural) { 676 if (dm->sfNatural) { 677 if (ishdf5) { 678 #if defined(PETSC_HAVE_HDF5) 679 Vec v; 680 const char *vecname; 681 682 PetscCall(DMGetGlobalVector(dm, &v)); 683 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 684 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 685 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 686 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 687 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 688 PetscCall(DMRestoreGlobalVector(dm, &v)); 689 #else 690 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 691 #endif 692 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 693 } 694 } else PetscCall(VecLoad_Default(originalv, viewer)); 695 } 696 PetscFunctionReturn(0); 697 } 698 699 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 700 { 701 PetscSection coordSection; 702 Vec coordinates; 703 DMLabel depthLabel, celltypeLabel; 704 const char *name[4]; 705 const PetscScalar *a; 706 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 707 708 PetscFunctionBegin; 709 PetscCall(DMGetDimension(dm, &dim)); 710 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 711 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 712 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 713 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 715 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 716 PetscCall(VecGetArrayRead(coordinates, &a)); 717 name[0] = "vertex"; 718 name[1] = "edge"; 719 name[dim-1] = "face"; 720 name[dim] = "cell"; 721 for (c = cStart; c < cEnd; ++c) { 722 PetscInt *closure = NULL; 723 PetscInt closureSize, cl, ct; 724 725 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 726 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 727 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 728 PetscCall(PetscViewerASCIIPushTab(viewer)); 729 for (cl = 0; cl < closureSize*2; cl += 2) { 730 PetscInt point = closure[cl], depth, dof, off, d, p; 731 732 if ((point < pStart) || (point >= pEnd)) continue; 733 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 734 if (!dof) continue; 735 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 736 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 737 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 738 for (p = 0; p < dof/dim; ++p) { 739 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 740 for (d = 0; d < dim; ++d) { 741 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 743 } 744 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 745 } 746 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 747 } 748 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 749 PetscCall(PetscViewerASCIIPopTab(viewer)); 750 } 751 PetscCall(VecRestoreArrayRead(coordinates, &a)); 752 PetscFunctionReturn(0); 753 } 754 755 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 756 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 757 758 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 759 { 760 PetscInt i; 761 762 PetscFunctionBegin; 763 if (dim > 3) { 764 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 765 } else { 766 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 767 768 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 769 switch (cs) { 770 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 771 case CS_POLAR: 772 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 773 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 774 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 775 break; 776 case CS_CYLINDRICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 779 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 780 trcoords[2] = coords[2]; 781 break; 782 case CS_SPHERICAL: 783 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 784 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 785 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 786 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 787 break; 788 } 789 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 790 } 791 PetscFunctionReturn(0); 792 } 793 794 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 795 { 796 DM_Plex *mesh = (DM_Plex*) dm->data; 797 DM cdm, cdmCell; 798 PetscSection coordSection, coordSectionCell; 799 Vec coordinates, coordinatesCell; 800 PetscViewerFormat format; 801 802 PetscFunctionBegin; 803 PetscCall(DMGetCoordinateDM(dm, &cdm)); 804 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 805 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 806 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 807 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 808 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 809 PetscCall(PetscViewerGetFormat(viewer, &format)); 810 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 811 const char *name; 812 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 813 PetscInt pStart, pEnd, p, numLabels, l; 814 PetscMPIInt rank, size; 815 816 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 817 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 818 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 819 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 820 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 821 PetscCall(DMGetDimension(dm, &dim)); 822 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 823 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 824 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 825 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 826 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 827 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 828 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 829 for (p = pStart; p < pEnd; ++p) { 830 PetscInt dof, off, s; 831 832 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 833 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 834 for (s = off; s < off+dof; ++s) { 835 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 836 } 837 } 838 PetscCall(PetscViewerFlush(viewer)); 839 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 840 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 841 for (p = pStart; p < pEnd; ++p) { 842 PetscInt dof, off, c; 843 844 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 845 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 846 for (c = off; c < off+dof; ++c) { 847 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 848 } 849 } 850 PetscCall(PetscViewerFlush(viewer)); 851 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 852 if (coordSection && coordinates) { 853 CoordSystem cs = CS_CARTESIAN; 854 const PetscScalar *array, *arrayCell = NULL; 855 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 856 PetscMPIInt rank; 857 const char *name; 858 859 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 860 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 861 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 862 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 863 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 864 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 865 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 866 pStart = PetscMin(pvStart, pcStart); 867 pEnd = PetscMax(pvEnd, pcEnd); 868 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 869 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 870 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 871 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 872 873 PetscCall(VecGetArrayRead(coordinates, &array)); 874 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 875 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 877 for (p = pStart; p < pEnd; ++p) { 878 PetscInt dof, off; 879 880 if (p >= pvStart && p < pvEnd) { 881 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 882 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 883 if (dof) { 884 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 885 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 886 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 887 } 888 } 889 if (cdmCell && p >= pcStart && p < pcEnd) { 890 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 891 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 892 if (dof) { 893 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 894 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 896 } 897 } 898 } 899 PetscCall(PetscViewerFlush(viewer)); 900 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 901 PetscCall(VecRestoreArrayRead(coordinates, &array)); 902 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 903 } 904 PetscCall(DMGetNumLabels(dm, &numLabels)); 905 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 906 for (l = 0; l < numLabels; ++l) { 907 DMLabel label; 908 PetscBool isdepth; 909 const char *name; 910 911 PetscCall(DMGetLabelName(dm, l, &name)); 912 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 913 if (isdepth) continue; 914 PetscCall(DMGetLabel(dm, name, &label)); 915 PetscCall(DMLabelView(label, viewer)); 916 } 917 if (size > 1) { 918 PetscSF sf; 919 920 PetscCall(DMGetPointSF(dm, &sf)); 921 PetscCall(PetscSFView(sf, viewer)); 922 } 923 PetscCall(PetscViewerFlush(viewer)); 924 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 925 const char *name, *color; 926 const char *defcolors[3] = {"gray", "orange", "green"}; 927 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 928 char lname[PETSC_MAX_PATH_LEN]; 929 PetscReal scale = 2.0; 930 PetscReal tikzscale = 1.0; 931 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 932 double tcoords[3]; 933 PetscScalar *coords; 934 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 935 PetscMPIInt rank, size; 936 char **names, **colors, **lcolors; 937 PetscBool flg, lflg; 938 PetscBT wp = NULL; 939 PetscInt pEnd, pStart; 940 941 PetscCall(DMGetDimension(dm, &dim)); 942 PetscCall(DMPlexGetDepth(dm, &depth)); 943 PetscCall(DMGetNumLabels(dm, &numLabels)); 944 numLabels = PetscMax(numLabels, 10); 945 numColors = 10; 946 numLColors = 10; 947 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 948 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 949 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 950 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 951 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 952 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 953 n = 4; 954 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 955 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 956 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 957 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 958 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 959 if (!useLabels) numLabels = 0; 960 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 961 if (!useColors) { 962 numColors = 3; 963 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 964 } 965 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 966 if (!useColors) { 967 numLColors = 4; 968 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 969 } 970 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 971 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 972 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 973 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 974 if (depth < dim) plotEdges = PETSC_FALSE; 975 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 976 977 /* filter points with labelvalue != labeldefaultvalue */ 978 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 979 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 980 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 981 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 982 if (lflg) { 983 DMLabel lbl; 984 985 PetscCall(DMGetLabel(dm, lname, &lbl)); 986 if (lbl) { 987 PetscInt val, defval; 988 989 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 990 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 991 for (c = pStart; c < pEnd; c++) { 992 PetscInt *closure = NULL; 993 PetscInt closureSize; 994 995 PetscCall(DMLabelGetValue(lbl, c, &val)); 996 if (val == defval) continue; 997 998 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 999 for (p = 0; p < closureSize*2; p += 2) { 1000 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1001 } 1002 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1003 } 1004 } 1005 } 1006 1007 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1008 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1009 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1011 \\documentclass[tikz]{standalone}\n\n\ 1012 \\usepackage{pgflibraryshapes}\n\ 1013 \\usetikzlibrary{backgrounds}\n\ 1014 \\usetikzlibrary{arrows}\n\ 1015 \\begin{document}\n")); 1016 if (size > 1) { 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1018 for (p = 0; p < size; ++p) { 1019 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1021 } 1022 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1023 } 1024 if (drawHasse) { 1025 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1026 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1032 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1033 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1034 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1035 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1037 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1039 } 1040 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1041 1042 /* Plot vertices */ 1043 PetscCall(VecGetArray(coordinates, &coords)); 1044 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1045 for (v = vStart; v < vEnd; ++v) { 1046 PetscInt off, dof, d; 1047 PetscBool isLabeled = PETSC_FALSE; 1048 1049 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1050 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1051 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1052 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1053 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1054 for (d = 0; d < dof; ++d) { 1055 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1056 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1057 } 1058 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1059 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1060 for (d = 0; d < dof; ++d) { 1061 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1062 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1063 } 1064 if (drawHasse) color = colors[0%numColors]; 1065 else color = colors[rank%numColors]; 1066 for (l = 0; l < numLabels; ++l) { 1067 PetscInt val; 1068 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1069 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1070 } 1071 if (drawNumbers[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1073 } else if (drawColors[0]) { 1074 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1075 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1076 } 1077 PetscCall(VecRestoreArray(coordinates, &coords)); 1078 PetscCall(PetscViewerFlush(viewer)); 1079 /* Plot edges */ 1080 if (plotEdges) { 1081 PetscCall(VecGetArray(coordinates, &coords)); 1082 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1083 for (e = eStart; e < eEnd; ++e) { 1084 const PetscInt *cone; 1085 PetscInt coneSize, offA, offB, dof, d; 1086 1087 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1088 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1089 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1090 PetscCall(DMPlexGetCone(dm, e, &cone)); 1091 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1092 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1093 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1094 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1095 for (d = 0; d < dof; ++d) { 1096 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1097 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1098 } 1099 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1100 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1101 for (d = 0; d < dof; ++d) { 1102 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1104 } 1105 if (drawHasse) color = colors[1%numColors]; 1106 else color = colors[rank%numColors]; 1107 for (l = 0; l < numLabels; ++l) { 1108 PetscInt val; 1109 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1110 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1111 } 1112 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1113 } 1114 PetscCall(VecRestoreArray(coordinates, &coords)); 1115 PetscCall(PetscViewerFlush(viewer)); 1116 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1117 } 1118 /* Plot cells */ 1119 if (dim == 3 || !drawNumbers[1]) { 1120 for (e = eStart; e < eEnd; ++e) { 1121 const PetscInt *cone; 1122 1123 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1124 color = colors[rank%numColors]; 1125 for (l = 0; l < numLabels; ++l) { 1126 PetscInt val; 1127 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1128 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1129 } 1130 PetscCall(DMPlexGetCone(dm, e, &cone)); 1131 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1132 } 1133 } else { 1134 DMPolytopeType ct; 1135 1136 /* Drawing a 2D polygon */ 1137 for (c = cStart; c < cEnd; ++c) { 1138 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1139 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1140 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1141 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1142 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1143 const PetscInt *cone; 1144 PetscInt coneSize, e; 1145 1146 PetscCall(DMPlexGetCone(dm, c, &cone)); 1147 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1148 for (e = 0; e < coneSize; ++e) { 1149 const PetscInt *econe; 1150 1151 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1152 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1153 } 1154 } else { 1155 PetscInt *closure = NULL; 1156 PetscInt closureSize, Nv = 0, v; 1157 1158 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1159 for (p = 0; p < closureSize*2; p += 2) { 1160 const PetscInt point = closure[p]; 1161 1162 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1163 } 1164 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1165 for (v = 0; v <= Nv; ++v) { 1166 const PetscInt vertex = closure[v%Nv]; 1167 1168 if (v > 0) { 1169 if (plotEdges) { 1170 const PetscInt *edge; 1171 PetscInt endpoints[2], ne; 1172 1173 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1174 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1175 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1176 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1177 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1178 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1179 } 1180 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1181 } 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1183 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1184 } 1185 } 1186 } 1187 for (c = cStart; c < cEnd; ++c) { 1188 double ccoords[3] = {0.0, 0.0, 0.0}; 1189 PetscBool isLabeled = PETSC_FALSE; 1190 PetscScalar *cellCoords = NULL; 1191 const PetscScalar *array; 1192 PetscInt numCoords, cdim, d; 1193 PetscBool isDG; 1194 1195 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1196 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1197 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1198 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1199 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1200 for (p = 0; p < numCoords/cdim; ++p) { 1201 for (d = 0; d < cdim; ++d) { 1202 tcoords[d] = (double) (scale*PetscRealPart(cellCoords[p*cdim+d])); 1203 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1204 } 1205 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1206 if (cdim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1207 for (d = 0; d < dim; ++d) {ccoords[d] += tcoords[d];} 1208 } 1209 for (d = 0; d < cdim; ++d) {ccoords[d] /= (numCoords/cdim);} 1210 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1211 for (d = 0; d < cdim; ++d) { 1212 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1213 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1214 } 1215 if (drawHasse) color = colors[depth%numColors]; 1216 else color = colors[rank%numColors]; 1217 for (l = 0; l < numLabels; ++l) { 1218 PetscInt val; 1219 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1220 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1221 } 1222 if (drawNumbers[dim]) { 1223 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1224 } else if (drawColors[dim]) { 1225 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1226 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1227 } 1228 if (drawHasse) { 1229 color = colors[depth%numColors]; 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1235 1236 color = colors[1%numColors]; 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1242 1243 color = colors[0%numColors]; 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1249 1250 for (p = pStart; p < pEnd; ++p) { 1251 const PetscInt *cone; 1252 PetscInt coneSize, cp; 1253 1254 PetscCall(DMPlexGetCone(dm, p, &cone)); 1255 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1256 for (cp = 0; cp < coneSize; ++cp) { 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1258 } 1259 } 1260 } 1261 PetscCall(PetscViewerFlush(viewer)); 1262 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1264 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1265 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1266 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1267 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1268 PetscCall(PetscFree3(names, colors, lcolors)); 1269 PetscCall(PetscBTDestroy(&wp)); 1270 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1271 Vec cown,acown; 1272 VecScatter sct; 1273 ISLocalToGlobalMapping g2l; 1274 IS gid,acis; 1275 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1276 MPI_Group ggroup,ngroup; 1277 PetscScalar *array,nid; 1278 const PetscInt *idxs; 1279 PetscInt *idxs2,*start,*adjacency,*work; 1280 PetscInt64 lm[3],gm[3]; 1281 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1282 PetscMPIInt d1,d2,rank; 1283 1284 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1285 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1286 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1287 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1288 #endif 1289 if (ncomm != MPI_COMM_NULL) { 1290 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1291 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1292 d1 = 0; 1293 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1294 nid = d2; 1295 PetscCallMPI(MPI_Group_free(&ggroup)); 1296 PetscCallMPI(MPI_Group_free(&ngroup)); 1297 PetscCallMPI(MPI_Comm_free(&ncomm)); 1298 } else nid = 0.0; 1299 1300 /* Get connectivity */ 1301 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1302 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1303 1304 /* filter overlapped local cells */ 1305 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1306 PetscCall(ISGetIndices(gid,&idxs)); 1307 PetscCall(ISGetLocalSize(gid,&cum)); 1308 PetscCall(PetscMalloc1(cum,&idxs2)); 1309 for (c = cStart, cum = 0; c < cEnd; c++) { 1310 if (idxs[c-cStart] < 0) continue; 1311 idxs2[cum++] = idxs[c-cStart]; 1312 } 1313 PetscCall(ISRestoreIndices(gid,&idxs)); 1314 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1315 PetscCall(ISDestroy(&gid)); 1316 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1317 1318 /* support for node-aware cell locality */ 1319 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1320 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1321 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1322 PetscCall(VecGetArray(cown,&array)); 1323 for (c = 0; c < numVertices; c++) array[c] = nid; 1324 PetscCall(VecRestoreArray(cown,&array)); 1325 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1326 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1327 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1328 PetscCall(ISDestroy(&acis)); 1329 PetscCall(VecScatterDestroy(&sct)); 1330 PetscCall(VecDestroy(&cown)); 1331 1332 /* compute edgeCut */ 1333 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1334 PetscCall(PetscMalloc1(cum,&work)); 1335 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1336 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1337 PetscCall(ISDestroy(&gid)); 1338 PetscCall(VecGetArray(acown,&array)); 1339 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1340 PetscInt totl; 1341 1342 totl = start[c+1]-start[c]; 1343 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1344 for (i = 0; i < totl; i++) { 1345 if (work[i] < 0) { 1346 ect += 1; 1347 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1348 } 1349 } 1350 } 1351 PetscCall(PetscFree(work)); 1352 PetscCall(VecRestoreArray(acown,&array)); 1353 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1354 lm[1] = -numVertices; 1355 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1356 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1357 lm[0] = ect; /* edgeCut */ 1358 lm[1] = ectn; /* node-aware edgeCut */ 1359 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1360 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1361 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1362 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1363 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1364 #else 1365 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1366 #endif 1367 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1368 PetscCall(PetscFree(start)); 1369 PetscCall(PetscFree(adjacency)); 1370 PetscCall(VecDestroy(&acown)); 1371 } else { 1372 const char *name; 1373 PetscInt *sizes, *hybsizes, *ghostsizes; 1374 PetscInt locDepth, depth, cellHeight, dim, d; 1375 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1376 PetscInt numLabels, l, maxSize = 17; 1377 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1378 MPI_Comm comm; 1379 PetscMPIInt size, rank; 1380 1381 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1382 PetscCallMPI(MPI_Comm_size(comm, &size)); 1383 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1384 PetscCall(DMGetDimension(dm, &dim)); 1385 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1386 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1387 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1388 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1389 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1390 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1391 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1392 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1393 gcNum = gcEnd - gcStart; 1394 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1395 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1396 for (d = 0; d <= depth; d++) { 1397 PetscInt Nc[2] = {0, 0}, ict; 1398 1399 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1400 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1401 ict = ct0; 1402 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1403 ct0 = (DMPolytopeType) ict; 1404 for (p = pStart; p < pEnd; ++p) { 1405 DMPolytopeType ct; 1406 1407 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1408 if (ct == ct0) ++Nc[0]; 1409 else ++Nc[1]; 1410 } 1411 if (size < maxSize) { 1412 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1413 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1414 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1416 for (p = 0; p < size; ++p) { 1417 if (rank == 0) { 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1419 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1420 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1421 } 1422 } 1423 } else { 1424 PetscInt locMinMax[2]; 1425 1426 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1427 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1428 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1429 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1430 if (d == depth) { 1431 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1432 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1433 } 1434 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1436 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1437 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1438 } 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1440 } 1441 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1442 { 1443 const PetscReal *maxCell; 1444 const PetscReal *L; 1445 PetscBool localized; 1446 1447 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1448 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1449 if (L || localized) { 1450 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1451 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1452 if (L) { 1453 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1454 for (d = 0; d < dim; ++d) { 1455 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1456 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1457 } 1458 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1459 } 1460 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1461 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1462 } 1463 } 1464 PetscCall(DMGetNumLabels(dm, &numLabels)); 1465 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1466 for (l = 0; l < numLabels; ++l) { 1467 DMLabel label; 1468 const char *name; 1469 IS valueIS; 1470 const PetscInt *values; 1471 PetscInt numValues, v; 1472 1473 PetscCall(DMGetLabelName(dm, l, &name)); 1474 PetscCall(DMGetLabel(dm, name, &label)); 1475 PetscCall(DMLabelGetNumValues(label, &numValues)); 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1477 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1478 PetscCall(ISGetIndices(valueIS, &values)); 1479 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1480 for (v = 0; v < numValues; ++v) { 1481 PetscInt size; 1482 1483 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1484 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1485 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1486 } 1487 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1488 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1489 PetscCall(ISRestoreIndices(valueIS, &values)); 1490 PetscCall(ISDestroy(&valueIS)); 1491 } 1492 { 1493 char **labelNames; 1494 PetscInt Nl = numLabels; 1495 PetscBool flg; 1496 1497 PetscCall(PetscMalloc1(Nl, &labelNames)); 1498 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1499 for (l = 0; l < Nl; ++l) { 1500 DMLabel label; 1501 1502 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1503 if (flg) { 1504 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1505 PetscCall(DMLabelView(label, viewer)); 1506 } 1507 PetscCall(PetscFree(labelNames[l])); 1508 } 1509 PetscCall(PetscFree(labelNames)); 1510 } 1511 /* If no fields are specified, people do not want to see adjacency */ 1512 if (dm->Nf) { 1513 PetscInt f; 1514 1515 for (f = 0; f < dm->Nf; ++f) { 1516 const char *name; 1517 1518 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1519 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1520 PetscCall(PetscViewerASCIIPushTab(viewer)); 1521 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1522 if (dm->fields[f].adjacency[0]) { 1523 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1524 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1525 } else { 1526 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1527 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1528 } 1529 PetscCall(PetscViewerASCIIPopTab(viewer)); 1530 } 1531 } 1532 PetscCall(DMGetCoarseDM(dm, &cdm)); 1533 if (cdm) { 1534 PetscCall(PetscViewerASCIIPushTab(viewer)); 1535 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1536 PetscCall(PetscViewerASCIIPopTab(viewer)); 1537 } 1538 } 1539 PetscFunctionReturn(0); 1540 } 1541 1542 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1543 { 1544 DMPolytopeType ct; 1545 PetscMPIInt rank; 1546 PetscInt cdim; 1547 1548 PetscFunctionBegin; 1549 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1550 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1551 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1552 switch (ct) { 1553 case DM_POLYTOPE_SEGMENT: 1554 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1555 switch (cdim) { 1556 case 1: 1557 { 1558 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1559 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1560 1561 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1562 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1563 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1564 } 1565 break; 1566 case 2: 1567 { 1568 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1569 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1570 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1571 1572 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1573 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1574 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1575 } 1576 break; 1577 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1578 } 1579 break; 1580 case DM_POLYTOPE_TRIANGLE: 1581 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1582 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1583 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1584 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1587 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1588 break; 1589 case DM_POLYTOPE_QUADRILATERAL: 1590 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1591 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1592 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1593 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1594 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1595 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1596 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1597 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1598 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1599 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1602 break; 1603 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1604 } 1605 PetscFunctionReturn(0); 1606 } 1607 1608 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1609 { 1610 DMPolytopeType ct; 1611 PetscReal centroid[2] = {0., 0.}; 1612 PetscMPIInt rank; 1613 PetscInt fillColor, v, e, d; 1614 1615 PetscFunctionBegin; 1616 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1617 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1618 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1619 switch (ct) { 1620 case DM_POLYTOPE_TRIANGLE: 1621 { 1622 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1623 1624 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1625 for (e = 0; e < 3; ++e) { 1626 refCoords[0] = refVertices[e*2+0]; 1627 refCoords[1] = refVertices[e*2+1]; 1628 for (d = 1; d <= edgeDiv; ++d) { 1629 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1630 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1631 } 1632 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1633 for (d = 0; d < edgeDiv; ++d) { 1634 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1635 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1636 } 1637 } 1638 } 1639 break; 1640 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1641 } 1642 PetscFunctionReturn(0); 1643 } 1644 1645 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1646 { 1647 PetscDraw draw; 1648 DM cdm; 1649 PetscSection coordSection; 1650 Vec coordinates; 1651 const PetscScalar *coords; 1652 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1653 PetscReal *refCoords, *edgeCoords; 1654 PetscBool isnull, drawAffine = PETSC_TRUE; 1655 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1656 1657 PetscFunctionBegin; 1658 PetscCall(DMGetCoordinateDim(dm, &dim)); 1659 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1660 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1661 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1662 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1663 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1664 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1665 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1666 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1667 1668 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1669 PetscCall(PetscDrawIsNull(draw, &isnull)); 1670 if (isnull) PetscFunctionReturn(0); 1671 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1672 1673 PetscCall(VecGetLocalSize(coordinates, &N)); 1674 PetscCall(VecGetArrayRead(coordinates, &coords)); 1675 for (c = 0; c < N; c += dim) { 1676 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1677 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1678 } 1679 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1680 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1681 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1682 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1683 PetscCall(PetscDrawClear(draw)); 1684 1685 for (c = cStart; c < cEnd; ++c) { 1686 PetscScalar *coords = NULL; 1687 PetscInt numCoords; 1688 1689 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1690 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1691 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1692 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1693 } 1694 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1695 PetscCall(PetscDrawFlush(draw)); 1696 PetscCall(PetscDrawPause(draw)); 1697 PetscCall(PetscDrawSave(draw)); 1698 PetscFunctionReturn(0); 1699 } 1700 1701 #if defined(PETSC_HAVE_EXODUSII) 1702 #include <exodusII.h> 1703 #include <petscviewerexodusii.h> 1704 #endif 1705 1706 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1707 { 1708 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1709 char name[PETSC_MAX_PATH_LEN]; 1710 1711 PetscFunctionBegin; 1712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1713 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1714 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1715 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1716 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1717 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERCGNS, &iscgns)); 1721 if (iascii) { 1722 PetscViewerFormat format; 1723 PetscCall(PetscViewerGetFormat(viewer, &format)); 1724 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1725 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1726 } else if (ishdf5) { 1727 #if defined(PETSC_HAVE_HDF5) 1728 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1729 #else 1730 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1731 #endif 1732 } else if (isvtk) { 1733 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1734 } else if (isdraw) { 1735 PetscCall(DMPlexView_Draw(dm, viewer)); 1736 } else if (isglvis) { 1737 PetscCall(DMPlexView_GLVis(dm, viewer)); 1738 #if defined(PETSC_HAVE_EXODUSII) 1739 } else if (isexodus) { 1740 /* 1741 exodusII requires that all sets be part of exactly one cell set. 1742 If the dm does not have a "Cell Sets" label defined, we create one 1743 with ID 1, containig all cells. 1744 Note that if the Cell Sets label is defined but does not cover all cells, 1745 we may still have a problem. This should probably be checked here or in the viewer; 1746 */ 1747 PetscInt numCS; 1748 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1749 if (!numCS) { 1750 PetscInt cStart, cEnd, c; 1751 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1752 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1753 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1754 } 1755 PetscCall(DMView_PlexExodusII(dm, viewer)); 1756 #endif 1757 #if defined(PETSC_HAVE_CGNS) 1758 } else if (iscgns) { 1759 PetscCall(DMView_PlexCGNS(dm, viewer)); 1760 #endif 1761 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1762 /* Optionally view the partition */ 1763 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1764 if (flg) { 1765 Vec ranks; 1766 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1767 PetscCall(VecView(ranks, viewer)); 1768 PetscCall(VecDestroy(&ranks)); 1769 } 1770 /* Optionally view a label */ 1771 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1772 if (flg) { 1773 DMLabel label; 1774 Vec val; 1775 1776 PetscCall(DMGetLabel(dm, name, &label)); 1777 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1778 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1779 PetscCall(VecView(val, viewer)); 1780 PetscCall(VecDestroy(&val)); 1781 } 1782 PetscFunctionReturn(0); 1783 } 1784 1785 /*@ 1786 DMPlexTopologyView - Saves a DMPlex topology into a file 1787 1788 Collective on DM 1789 1790 Input Parameters: 1791 + dm - The DM whose topology is to be saved 1792 - viewer - The PetscViewer for saving 1793 1794 Level: advanced 1795 1796 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1797 @*/ 1798 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1799 { 1800 PetscBool ishdf5; 1801 1802 PetscFunctionBegin; 1803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1804 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1805 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1806 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1807 if (ishdf5) { 1808 #if defined(PETSC_HAVE_HDF5) 1809 PetscViewerFormat format; 1810 PetscCall(PetscViewerGetFormat(viewer, &format)); 1811 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1812 IS globalPointNumbering; 1813 1814 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1815 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1816 PetscCall(ISDestroy(&globalPointNumbering)); 1817 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1818 #else 1819 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1820 #endif 1821 } 1822 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1823 PetscFunctionReturn(0); 1824 } 1825 1826 /*@ 1827 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1828 1829 Collective on DM 1830 1831 Input Parameters: 1832 + dm - The DM whose coordinates are to be saved 1833 - viewer - The PetscViewer for saving 1834 1835 Level: advanced 1836 1837 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1838 @*/ 1839 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1840 { 1841 PetscBool ishdf5; 1842 1843 PetscFunctionBegin; 1844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1845 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1846 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1847 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1848 if (ishdf5) { 1849 #if defined(PETSC_HAVE_HDF5) 1850 PetscViewerFormat format; 1851 PetscCall(PetscViewerGetFormat(viewer, &format)); 1852 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1853 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1854 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1855 #else 1856 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1857 #endif 1858 } 1859 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*@ 1864 DMPlexLabelsView - Saves DMPlex labels into a file 1865 1866 Collective on DM 1867 1868 Input Parameters: 1869 + dm - The DM whose labels are to be saved 1870 - viewer - The PetscViewer for saving 1871 1872 Level: advanced 1873 1874 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1875 @*/ 1876 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1877 { 1878 PetscBool ishdf5; 1879 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1882 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1883 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1884 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1885 if (ishdf5) { 1886 #if defined(PETSC_HAVE_HDF5) 1887 IS globalPointNumbering; 1888 PetscViewerFormat format; 1889 1890 PetscCall(PetscViewerGetFormat(viewer, &format)); 1891 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1892 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1893 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1894 PetscCall(ISDestroy(&globalPointNumbering)); 1895 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1896 #else 1897 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1898 #endif 1899 } 1900 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1901 PetscFunctionReturn(0); 1902 } 1903 1904 /*@ 1905 DMPlexSectionView - Saves a section associated with a DMPlex 1906 1907 Collective on DM 1908 1909 Input Parameters: 1910 + dm - The DM that contains the topology on which the section to be saved is defined 1911 . viewer - The PetscViewer for saving 1912 - sectiondm - The DM that contains the section to be saved 1913 1914 Level: advanced 1915 1916 Notes: 1917 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1918 1919 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1920 1921 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1922 @*/ 1923 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1924 { 1925 PetscBool ishdf5; 1926 1927 PetscFunctionBegin; 1928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1929 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1930 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1932 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1933 if (ishdf5) { 1934 #if defined(PETSC_HAVE_HDF5) 1935 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1936 #else 1937 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1938 #endif 1939 } 1940 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1941 PetscFunctionReturn(0); 1942 } 1943 1944 /*@ 1945 DMPlexGlobalVectorView - Saves a global vector 1946 1947 Collective on DM 1948 1949 Input Parameters: 1950 + dm - The DM that represents the topology 1951 . viewer - The PetscViewer to save data with 1952 . sectiondm - The DM that contains the global section on which vec is defined 1953 - vec - The global vector to be saved 1954 1955 Level: advanced 1956 1957 Notes: 1958 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1959 1960 Typical calling sequence 1961 $ DMCreate(PETSC_COMM_WORLD, &dm); 1962 $ DMSetType(dm, DMPLEX); 1963 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1964 $ DMClone(dm, §iondm); 1965 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1966 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1967 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1968 $ PetscSectionSetChart(section, pStart, pEnd); 1969 $ PetscSectionSetUp(section); 1970 $ DMSetLocalSection(sectiondm, section); 1971 $ PetscSectionDestroy(§ion); 1972 $ DMGetGlobalVector(sectiondm, &vec); 1973 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1974 $ DMPlexTopologyView(dm, viewer); 1975 $ DMPlexSectionView(dm, viewer, sectiondm); 1976 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1977 $ DMRestoreGlobalVector(sectiondm, &vec); 1978 $ DMDestroy(§iondm); 1979 $ DMDestroy(&dm); 1980 1981 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1982 @*/ 1983 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1984 { 1985 PetscBool ishdf5; 1986 1987 PetscFunctionBegin; 1988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1989 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1990 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1991 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1992 /* Check consistency */ 1993 { 1994 PetscSection section; 1995 PetscBool includesConstraints; 1996 PetscInt m, m1; 1997 1998 PetscCall(VecGetLocalSize(vec, &m1)); 1999 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2000 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2001 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2002 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2003 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2004 } 2005 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2006 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2007 if (ishdf5) { 2008 #if defined(PETSC_HAVE_HDF5) 2009 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2010 #else 2011 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2012 #endif 2013 } 2014 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2015 PetscFunctionReturn(0); 2016 } 2017 2018 /*@ 2019 DMPlexLocalVectorView - Saves a local vector 2020 2021 Collective on DM 2022 2023 Input Parameters: 2024 + dm - The DM that represents the topology 2025 . viewer - The PetscViewer to save data with 2026 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2027 - vec - The local vector to be saved 2028 2029 Level: advanced 2030 2031 Notes: 2032 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2033 2034 Typical calling sequence 2035 $ DMCreate(PETSC_COMM_WORLD, &dm); 2036 $ DMSetType(dm, DMPLEX); 2037 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2038 $ DMClone(dm, §iondm); 2039 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2040 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2041 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2042 $ PetscSectionSetChart(section, pStart, pEnd); 2043 $ PetscSectionSetUp(section); 2044 $ DMSetLocalSection(sectiondm, section); 2045 $ DMGetLocalVector(sectiondm, &vec); 2046 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2047 $ DMPlexTopologyView(dm, viewer); 2048 $ DMPlexSectionView(dm, viewer, sectiondm); 2049 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2050 $ DMRestoreLocalVector(sectiondm, &vec); 2051 $ DMDestroy(§iondm); 2052 $ DMDestroy(&dm); 2053 2054 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2055 @*/ 2056 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2064 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2065 /* Check consistency */ 2066 { 2067 PetscSection section; 2068 PetscBool includesConstraints; 2069 PetscInt m, m1; 2070 2071 PetscCall(VecGetLocalSize(vec, &m1)); 2072 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2073 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2074 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2075 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2076 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2077 } 2078 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2079 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2080 if (ishdf5) { 2081 #if defined(PETSC_HAVE_HDF5) 2082 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2083 #else 2084 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2085 #endif 2086 } 2087 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2088 PetscFunctionReturn(0); 2089 } 2090 2091 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2092 { 2093 PetscBool ishdf5; 2094 2095 PetscFunctionBegin; 2096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2097 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2098 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2099 if (ishdf5) { 2100 #if defined(PETSC_HAVE_HDF5) 2101 PetscViewerFormat format; 2102 PetscCall(PetscViewerGetFormat(viewer, &format)); 2103 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2104 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2105 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2106 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2108 PetscFunctionReturn(0); 2109 #else 2110 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2111 #endif 2112 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2113 } 2114 2115 /*@ 2116 DMPlexTopologyLoad - Loads a topology into a DMPlex 2117 2118 Collective on DM 2119 2120 Input Parameters: 2121 + dm - The DM into which the topology is loaded 2122 - viewer - The PetscViewer for the saved topology 2123 2124 Output Parameters: 2125 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2126 2127 Level: advanced 2128 2129 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2130 @*/ 2131 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2132 { 2133 PetscBool ishdf5; 2134 2135 PetscFunctionBegin; 2136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2137 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2138 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2139 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2140 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2141 if (ishdf5) { 2142 #if defined(PETSC_HAVE_HDF5) 2143 PetscViewerFormat format; 2144 PetscCall(PetscViewerGetFormat(viewer, &format)); 2145 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2146 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2147 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2148 #else 2149 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2150 #endif 2151 } 2152 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2153 PetscFunctionReturn(0); 2154 } 2155 2156 /*@ 2157 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2158 2159 Collective on DM 2160 2161 Input Parameters: 2162 + dm - The DM into which the coordinates are loaded 2163 . viewer - The PetscViewer for the saved coordinates 2164 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2165 2166 Level: advanced 2167 2168 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2169 @*/ 2170 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2171 { 2172 PetscBool ishdf5; 2173 2174 PetscFunctionBegin; 2175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2176 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2177 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2178 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2179 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2180 if (ishdf5) { 2181 #if defined(PETSC_HAVE_HDF5) 2182 PetscViewerFormat format; 2183 PetscCall(PetscViewerGetFormat(viewer, &format)); 2184 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2185 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2186 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2187 #else 2188 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2189 #endif 2190 } 2191 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2192 PetscFunctionReturn(0); 2193 } 2194 2195 /*@ 2196 DMPlexLabelsLoad - Loads labels into a DMPlex 2197 2198 Collective on DM 2199 2200 Input Parameters: 2201 + dm - The DM into which the labels are loaded 2202 . viewer - The PetscViewer for the saved labels 2203 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2204 2205 Level: advanced 2206 2207 Notes: 2208 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2209 2210 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2211 @*/ 2212 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2213 { 2214 PetscBool ishdf5; 2215 2216 PetscFunctionBegin; 2217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2218 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2219 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2220 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2221 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2222 if (ishdf5) { 2223 #if defined(PETSC_HAVE_HDF5) 2224 PetscViewerFormat format; 2225 2226 PetscCall(PetscViewerGetFormat(viewer, &format)); 2227 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2228 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2229 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2230 #else 2231 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2232 #endif 2233 } 2234 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2235 PetscFunctionReturn(0); 2236 } 2237 2238 /*@ 2239 DMPlexSectionLoad - Loads section into a DMPlex 2240 2241 Collective on DM 2242 2243 Input Parameters: 2244 + dm - The DM that represents the topology 2245 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2246 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2247 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2248 2249 Output Parameters 2250 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2251 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2252 2253 Level: advanced 2254 2255 Notes: 2256 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2257 2258 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2259 2260 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2261 2262 Example using 2 processes: 2263 $ NX (number of points on dm): 4 2264 $ sectionA : the on-disk section 2265 $ vecA : a vector associated with sectionA 2266 $ sectionB : sectiondm's local section constructed in this function 2267 $ vecB (local) : a vector associated with sectiondm's local section 2268 $ vecB (global) : a vector associated with sectiondm's global section 2269 $ 2270 $ rank 0 rank 1 2271 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2272 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2273 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2274 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2275 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2276 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2277 $ sectionB->atlasDof : 1 0 1 | 1 3 2278 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2279 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2280 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2281 $ 2282 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2283 2284 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2285 @*/ 2286 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2287 { 2288 PetscBool ishdf5; 2289 2290 PetscFunctionBegin; 2291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2292 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2293 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2294 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2295 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2296 if (localDofSF) PetscValidPointer(localDofSF, 6); 2297 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2298 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2299 if (ishdf5) { 2300 #if defined(PETSC_HAVE_HDF5) 2301 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2302 #else 2303 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2304 #endif 2305 } 2306 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2307 PetscFunctionReturn(0); 2308 } 2309 2310 /*@ 2311 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2312 2313 Collective on DM 2314 2315 Input Parameters: 2316 + dm - The DM that represents the topology 2317 . viewer - The PetscViewer that represents the on-disk vector data 2318 . sectiondm - The DM that contains the global section on which vec is defined 2319 . sf - The SF that migrates the on-disk vector data into vec 2320 - vec - The global vector to set values of 2321 2322 Level: advanced 2323 2324 Notes: 2325 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2326 2327 Typical calling sequence 2328 $ DMCreate(PETSC_COMM_WORLD, &dm); 2329 $ DMSetType(dm, DMPLEX); 2330 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2331 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2332 $ DMClone(dm, §iondm); 2333 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2334 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2335 $ DMGetGlobalVector(sectiondm, &vec); 2336 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2337 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2338 $ DMRestoreGlobalVector(sectiondm, &vec); 2339 $ PetscSFDestroy(&gsf); 2340 $ PetscSFDestroy(&sfX); 2341 $ DMDestroy(§iondm); 2342 $ DMDestroy(&dm); 2343 2344 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2345 @*/ 2346 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2347 { 2348 PetscBool ishdf5; 2349 2350 PetscFunctionBegin; 2351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2352 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2353 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2354 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2355 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2356 /* Check consistency */ 2357 { 2358 PetscSection section; 2359 PetscBool includesConstraints; 2360 PetscInt m, m1; 2361 2362 PetscCall(VecGetLocalSize(vec, &m1)); 2363 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2364 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2365 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2366 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2367 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2368 } 2369 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2370 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2371 if (ishdf5) { 2372 #if defined(PETSC_HAVE_HDF5) 2373 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2374 #else 2375 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2376 #endif 2377 } 2378 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2379 PetscFunctionReturn(0); 2380 } 2381 2382 /*@ 2383 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2384 2385 Collective on DM 2386 2387 Input Parameters: 2388 + dm - The DM that represents the topology 2389 . viewer - The PetscViewer that represents the on-disk vector data 2390 . sectiondm - The DM that contains the local section on which vec is defined 2391 . sf - The SF that migrates the on-disk vector data into vec 2392 - vec - The local vector to set values of 2393 2394 Level: advanced 2395 2396 Notes: 2397 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2398 2399 Typical calling sequence 2400 $ DMCreate(PETSC_COMM_WORLD, &dm); 2401 $ DMSetType(dm, DMPLEX); 2402 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2403 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2404 $ DMClone(dm, §iondm); 2405 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2406 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2407 $ DMGetLocalVector(sectiondm, &vec); 2408 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2409 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2410 $ DMRestoreLocalVector(sectiondm, &vec); 2411 $ PetscSFDestroy(&lsf); 2412 $ PetscSFDestroy(&sfX); 2413 $ DMDestroy(§iondm); 2414 $ DMDestroy(&dm); 2415 2416 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2417 @*/ 2418 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2419 { 2420 PetscBool ishdf5; 2421 2422 PetscFunctionBegin; 2423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2424 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2425 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2426 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2427 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2428 /* Check consistency */ 2429 { 2430 PetscSection section; 2431 PetscBool includesConstraints; 2432 PetscInt m, m1; 2433 2434 PetscCall(VecGetLocalSize(vec, &m1)); 2435 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2436 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2437 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2438 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2439 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2440 } 2441 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2442 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2443 if (ishdf5) { 2444 #if defined(PETSC_HAVE_HDF5) 2445 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2446 #else 2447 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2448 #endif 2449 } 2450 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2451 PetscFunctionReturn(0); 2452 } 2453 2454 PetscErrorCode DMDestroy_Plex(DM dm) 2455 { 2456 DM_Plex *mesh = (DM_Plex*) dm->data; 2457 2458 PetscFunctionBegin; 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2461 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2462 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2463 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2464 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2465 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2466 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2467 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2468 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2469 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2470 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2471 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2472 if (--mesh->refct > 0) PetscFunctionReturn(0); 2473 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2474 PetscCall(PetscFree(mesh->cones)); 2475 PetscCall(PetscFree(mesh->coneOrientations)); 2476 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2477 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2478 PetscCall(PetscFree(mesh->supports)); 2479 PetscCall(PetscFree(mesh->facesTmp)); 2480 PetscCall(PetscFree(mesh->tetgenOpts)); 2481 PetscCall(PetscFree(mesh->triangleOpts)); 2482 PetscCall(PetscFree(mesh->transformType)); 2483 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2484 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2485 PetscCall(ISDestroy(&mesh->subpointIS)); 2486 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2487 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2488 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2489 PetscCall(ISDestroy(&mesh->anchorIS)); 2490 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2491 PetscCall(PetscFree(mesh->parents)); 2492 PetscCall(PetscFree(mesh->childIDs)); 2493 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2494 PetscCall(PetscFree(mesh->children)); 2495 PetscCall(DMDestroy(&mesh->referenceTree)); 2496 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2497 PetscCall(PetscFree(mesh->neighbors)); 2498 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2499 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2500 PetscCall(PetscFree(mesh)); 2501 PetscFunctionReturn(0); 2502 } 2503 2504 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2505 { 2506 PetscSection sectionGlobal; 2507 PetscInt bs = -1, mbs; 2508 PetscInt localSize, localStart = 0; 2509 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2510 MatType mtype; 2511 ISLocalToGlobalMapping ltog; 2512 2513 PetscFunctionBegin; 2514 PetscCall(MatInitializePackage()); 2515 mtype = dm->mattype; 2516 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2517 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2518 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2519 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2520 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2521 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2522 PetscCall(MatSetType(*J, mtype)); 2523 PetscCall(MatSetFromOptions(*J)); 2524 PetscCall(MatGetBlockSize(*J, &mbs)); 2525 if (mbs > 1) bs = mbs; 2526 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2527 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2528 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2529 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2530 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2531 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2532 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2533 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2534 if (!isShell) { 2535 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2536 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2537 PetscInt pStart, pEnd, p, dof, cdof; 2538 2539 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2540 2541 PetscCall(PetscCalloc1(localSize, &pblocks)); 2542 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2543 for (p = pStart; p < pEnd; ++p) { 2544 PetscInt bdof, offset; 2545 2546 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2547 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2548 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2549 for (PetscInt i=0; i < dof - cdof; i++) 2550 pblocks[offset - localStart + i] = dof - cdof; 2551 dof = dof < 0 ? -(dof+1) : dof; 2552 bdof = cdof && (dof-cdof) ? 1 : dof; 2553 if (dof) { 2554 if (bs < 0) {bs = bdof;} 2555 else if (bs != bdof) {bs = 1;} 2556 } 2557 } 2558 /* Must have same blocksize on all procs (some might have no points) */ 2559 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2560 bsLocal[1] = bs; 2561 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2562 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2563 else bs = bsMinMax[0]; 2564 bs = PetscMax(1,bs); 2565 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2566 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2567 PetscCall(MatSetBlockSize(*J, bs)); 2568 PetscCall(MatSetUp(*J)); 2569 } else { 2570 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2571 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2572 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2573 } 2574 { // Consolidate blocks 2575 PetscInt nblocks = 0; 2576 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2577 if (pblocks[i] == 0) continue; 2578 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2579 for (PetscInt j=1; j<pblocks[i]; j++) { 2580 PetscCheck(pblocks[i+j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i+j]); 2581 } 2582 } 2583 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2584 } 2585 PetscCall(PetscFree(pblocks)); 2586 } 2587 PetscCall(MatSetDM(*J, dm)); 2588 PetscFunctionReturn(0); 2589 } 2590 2591 /*@ 2592 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2593 2594 Not collective 2595 2596 Input Parameter: 2597 . mesh - The DMPlex 2598 2599 Output Parameters: 2600 . subsection - The subdomain section 2601 2602 Level: developer 2603 2604 .seealso: 2605 @*/ 2606 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2607 { 2608 DM_Plex *mesh = (DM_Plex*) dm->data; 2609 2610 PetscFunctionBegin; 2611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2612 if (!mesh->subdomainSection) { 2613 PetscSection section; 2614 PetscSF sf; 2615 2616 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2617 PetscCall(DMGetLocalSection(dm,§ion)); 2618 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2619 PetscCall(PetscSFDestroy(&sf)); 2620 } 2621 *subsection = mesh->subdomainSection; 2622 PetscFunctionReturn(0); 2623 } 2624 2625 /*@ 2626 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2627 2628 Not collective 2629 2630 Input Parameter: 2631 . mesh - The DMPlex 2632 2633 Output Parameters: 2634 + pStart - The first mesh point 2635 - pEnd - The upper bound for mesh points 2636 2637 Level: beginner 2638 2639 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2640 @*/ 2641 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2642 { 2643 DM_Plex *mesh = (DM_Plex*) dm->data; 2644 2645 PetscFunctionBegin; 2646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2647 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2648 PetscFunctionReturn(0); 2649 } 2650 2651 /*@ 2652 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2653 2654 Not collective 2655 2656 Input Parameters: 2657 + mesh - The DMPlex 2658 . pStart - The first mesh point 2659 - pEnd - The upper bound for mesh points 2660 2661 Output Parameters: 2662 2663 Level: beginner 2664 2665 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2666 @*/ 2667 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2668 { 2669 DM_Plex *mesh = (DM_Plex*) dm->data; 2670 2671 PetscFunctionBegin; 2672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2673 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2674 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2675 PetscFunctionReturn(0); 2676 } 2677 2678 /*@ 2679 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2680 2681 Not collective 2682 2683 Input Parameters: 2684 + mesh - The DMPlex 2685 - p - The point, which must lie in the chart set with DMPlexSetChart() 2686 2687 Output Parameter: 2688 . size - The cone size for point p 2689 2690 Level: beginner 2691 2692 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2693 @*/ 2694 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2695 { 2696 DM_Plex *mesh = (DM_Plex*) dm->data; 2697 2698 PetscFunctionBegin; 2699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2700 PetscValidIntPointer(size, 3); 2701 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2702 PetscFunctionReturn(0); 2703 } 2704 2705 /*@ 2706 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2707 2708 Not collective 2709 2710 Input Parameters: 2711 + mesh - The DMPlex 2712 . p - The point, which must lie in the chart set with DMPlexSetChart() 2713 - size - The cone size for point p 2714 2715 Output Parameter: 2716 2717 Note: 2718 This should be called after DMPlexSetChart(). 2719 2720 Level: beginner 2721 2722 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2723 @*/ 2724 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2725 { 2726 DM_Plex *mesh = (DM_Plex*) dm->data; 2727 2728 PetscFunctionBegin; 2729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2730 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2731 PetscFunctionReturn(0); 2732 } 2733 2734 /*@ 2735 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2736 2737 Not collective 2738 2739 Input Parameters: 2740 + mesh - The DMPlex 2741 . p - The point, which must lie in the chart set with DMPlexSetChart() 2742 - size - The additional cone size for point p 2743 2744 Output Parameter: 2745 2746 Note: 2747 This should be called after DMPlexSetChart(). 2748 2749 Level: beginner 2750 2751 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2752 @*/ 2753 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2754 { 2755 DM_Plex *mesh = (DM_Plex*) dm->data; 2756 PetscFunctionBegin; 2757 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2758 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2759 PetscFunctionReturn(0); 2760 } 2761 2762 /*@C 2763 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2764 2765 Not collective 2766 2767 Input Parameters: 2768 + dm - The DMPlex 2769 - p - The point, which must lie in the chart set with DMPlexSetChart() 2770 2771 Output Parameter: 2772 . cone - An array of points which are on the in-edges for point p 2773 2774 Level: beginner 2775 2776 Fortran Notes: 2777 Since it returns an array, this routine is only available in Fortran 90, and you must 2778 include petsc.h90 in your code. 2779 You must also call DMPlexRestoreCone() after you finish using the returned array. 2780 DMPlexRestoreCone() is not needed/available in C. 2781 2782 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2783 @*/ 2784 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2785 { 2786 DM_Plex *mesh = (DM_Plex*) dm->data; 2787 PetscInt off; 2788 2789 PetscFunctionBegin; 2790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2791 PetscValidPointer(cone, 3); 2792 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2793 *cone = &mesh->cones[off]; 2794 PetscFunctionReturn(0); 2795 } 2796 2797 /*@C 2798 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2799 2800 Not collective 2801 2802 Input Parameters: 2803 + dm - The DMPlex 2804 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2805 2806 Output Parameters: 2807 + pConesSection - PetscSection describing the layout of pCones 2808 - pCones - An array of points which are on the in-edges for the point set p 2809 2810 Level: intermediate 2811 2812 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2813 @*/ 2814 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2815 { 2816 PetscSection cs, newcs; 2817 PetscInt *cones; 2818 PetscInt *newarr=NULL; 2819 PetscInt n; 2820 2821 PetscFunctionBegin; 2822 PetscCall(DMPlexGetCones(dm, &cones)); 2823 PetscCall(DMPlexGetConeSection(dm, &cs)); 2824 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2825 if (pConesSection) *pConesSection = newcs; 2826 if (pCones) { 2827 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2828 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2829 } 2830 PetscFunctionReturn(0); 2831 } 2832 2833 /*@ 2834 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2835 2836 Not collective 2837 2838 Input Parameters: 2839 + dm - The DMPlex 2840 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2841 2842 Output Parameter: 2843 . expandedPoints - An array of vertices recursively expanded from input points 2844 2845 Level: advanced 2846 2847 Notes: 2848 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2849 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2850 2851 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2852 @*/ 2853 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2854 { 2855 IS *expandedPointsAll; 2856 PetscInt depth; 2857 2858 PetscFunctionBegin; 2859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2860 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2861 PetscValidPointer(expandedPoints, 3); 2862 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2863 *expandedPoints = expandedPointsAll[0]; 2864 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2865 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2866 PetscFunctionReturn(0); 2867 } 2868 2869 /*@ 2870 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2871 2872 Not collective 2873 2874 Input Parameters: 2875 + dm - The DMPlex 2876 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2877 2878 Output Parameters: 2879 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2880 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2881 - sections - (optional) An array of sections which describe mappings from points to their cone points 2882 2883 Level: advanced 2884 2885 Notes: 2886 Like DMPlexGetConeTuple() but recursive. 2887 2888 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2889 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2890 2891 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2892 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2893 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2894 2895 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2896 @*/ 2897 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2898 { 2899 const PetscInt *arr0=NULL, *cone=NULL; 2900 PetscInt *arr=NULL, *newarr=NULL; 2901 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2902 IS *expandedPoints_; 2903 PetscSection *sections_; 2904 2905 PetscFunctionBegin; 2906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2907 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2908 if (depth) PetscValidIntPointer(depth, 3); 2909 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2910 if (sections) PetscValidPointer(sections, 5); 2911 PetscCall(ISGetLocalSize(points, &n)); 2912 PetscCall(ISGetIndices(points, &arr0)); 2913 PetscCall(DMPlexGetDepth(dm, &depth_)); 2914 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2915 PetscCall(PetscCalloc1(depth_, §ions_)); 2916 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2917 for (d=depth_-1; d>=0; d--) { 2918 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2919 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2920 for (i=0; i<n; i++) { 2921 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2922 if (arr[i] >= start && arr[i] < end) { 2923 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2924 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2925 } else { 2926 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2927 } 2928 } 2929 PetscCall(PetscSectionSetUp(sections_[d])); 2930 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2931 PetscCall(PetscMalloc1(newn, &newarr)); 2932 for (i=0; i<n; i++) { 2933 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2934 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2935 if (cn > 1) { 2936 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2937 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2938 } else { 2939 newarr[co] = arr[i]; 2940 } 2941 } 2942 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2943 arr = newarr; 2944 n = newn; 2945 } 2946 PetscCall(ISRestoreIndices(points, &arr0)); 2947 *depth = depth_; 2948 if (expandedPoints) *expandedPoints = expandedPoints_; 2949 else { 2950 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2951 PetscCall(PetscFree(expandedPoints_)); 2952 } 2953 if (sections) *sections = sections_; 2954 else { 2955 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2956 PetscCall(PetscFree(sections_)); 2957 } 2958 PetscFunctionReturn(0); 2959 } 2960 2961 /*@ 2962 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2963 2964 Not collective 2965 2966 Input Parameters: 2967 + dm - The DMPlex 2968 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2969 2970 Output Parameters: 2971 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2972 . expandedPoints - (optional) An array of recursively expanded cones 2973 - sections - (optional) An array of sections which describe mappings from points to their cone points 2974 2975 Level: advanced 2976 2977 Notes: 2978 See DMPlexGetConeRecursive() for details. 2979 2980 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2981 @*/ 2982 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2983 { 2984 PetscInt d, depth_; 2985 2986 PetscFunctionBegin; 2987 PetscCall(DMPlexGetDepth(dm, &depth_)); 2988 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2989 if (depth) *depth = 0; 2990 if (expandedPoints) { 2991 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2992 PetscCall(PetscFree(*expandedPoints)); 2993 } 2994 if (sections) { 2995 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2996 PetscCall(PetscFree(*sections)); 2997 } 2998 PetscFunctionReturn(0); 2999 } 3000 3001 /*@ 3002 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3003 3004 Not collective 3005 3006 Input Parameters: 3007 + mesh - The DMPlex 3008 . p - The point, which must lie in the chart set with DMPlexSetChart() 3009 - cone - An array of points which are on the in-edges for point p 3010 3011 Output Parameter: 3012 3013 Note: 3014 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3015 3016 Level: beginner 3017 3018 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3019 @*/ 3020 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3021 { 3022 DM_Plex *mesh = (DM_Plex*) dm->data; 3023 PetscInt pStart, pEnd; 3024 PetscInt dof, off, c; 3025 3026 PetscFunctionBegin; 3027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3028 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3029 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3030 if (dof) PetscValidIntPointer(cone, 3); 3031 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3032 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3033 for (c = 0; c < dof; ++c) { 3034 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3035 mesh->cones[off+c] = cone[c]; 3036 } 3037 PetscFunctionReturn(0); 3038 } 3039 3040 /*@C 3041 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3042 3043 Not collective 3044 3045 Input Parameters: 3046 + mesh - The DMPlex 3047 - p - The point, which must lie in the chart set with DMPlexSetChart() 3048 3049 Output Parameter: 3050 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3051 integer giving the prescription for cone traversal. 3052 3053 Level: beginner 3054 3055 Notes: 3056 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3057 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3058 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3059 with the identity. 3060 3061 Fortran Notes: 3062 Since it returns an array, this routine is only available in Fortran 90, and you must 3063 include petsc.h90 in your code. 3064 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3065 DMPlexRestoreConeOrientation() is not needed/available in C. 3066 3067 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3068 @*/ 3069 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3070 { 3071 DM_Plex *mesh = (DM_Plex*) dm->data; 3072 PetscInt off; 3073 3074 PetscFunctionBegin; 3075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3076 if (PetscDefined(USE_DEBUG)) { 3077 PetscInt dof; 3078 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3079 if (dof) PetscValidPointer(coneOrientation, 3); 3080 } 3081 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3082 3083 *coneOrientation = &mesh->coneOrientations[off]; 3084 PetscFunctionReturn(0); 3085 } 3086 3087 /*@ 3088 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3089 3090 Not collective 3091 3092 Input Parameters: 3093 + mesh - The DMPlex 3094 . p - The point, which must lie in the chart set with DMPlexSetChart() 3095 - coneOrientation - An array of orientations 3096 Output Parameter: 3097 3098 Notes: 3099 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3100 3101 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3102 3103 Level: beginner 3104 3105 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3106 @*/ 3107 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3108 { 3109 DM_Plex *mesh = (DM_Plex*) dm->data; 3110 PetscInt pStart, pEnd; 3111 PetscInt dof, off, c; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3116 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3117 if (dof) PetscValidIntPointer(coneOrientation, 3); 3118 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3119 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3120 for (c = 0; c < dof; ++c) { 3121 PetscInt cdof, o = coneOrientation[c]; 3122 3123 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3124 PetscCheck(!o || (o >= -(cdof+1) && o < cdof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof+1), cdof); 3125 mesh->coneOrientations[off+c] = o; 3126 } 3127 PetscFunctionReturn(0); 3128 } 3129 3130 /*@ 3131 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3132 3133 Not collective 3134 3135 Input Parameters: 3136 + mesh - The DMPlex 3137 . p - The point, which must lie in the chart set with DMPlexSetChart() 3138 . conePos - The local index in the cone where the point should be put 3139 - conePoint - The mesh point to insert 3140 3141 Level: beginner 3142 3143 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3144 @*/ 3145 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3146 { 3147 DM_Plex *mesh = (DM_Plex*) dm->data; 3148 PetscInt pStart, pEnd; 3149 PetscInt dof, off; 3150 3151 PetscFunctionBegin; 3152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3153 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3154 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3155 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3156 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3157 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3158 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3159 mesh->cones[off+conePos] = conePoint; 3160 PetscFunctionReturn(0); 3161 } 3162 3163 /*@ 3164 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3165 3166 Not collective 3167 3168 Input Parameters: 3169 + mesh - The DMPlex 3170 . p - The point, which must lie in the chart set with DMPlexSetChart() 3171 . conePos - The local index in the cone where the point should be put 3172 - coneOrientation - The point orientation to insert 3173 3174 Level: beginner 3175 3176 Notes: 3177 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3178 3179 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3180 @*/ 3181 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3182 { 3183 DM_Plex *mesh = (DM_Plex*) dm->data; 3184 PetscInt pStart, pEnd; 3185 PetscInt dof, off; 3186 3187 PetscFunctionBegin; 3188 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3189 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3190 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3191 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3192 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3193 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3194 mesh->coneOrientations[off+conePos] = coneOrientation; 3195 PetscFunctionReturn(0); 3196 } 3197 3198 /*@ 3199 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3200 3201 Not collective 3202 3203 Input Parameters: 3204 + mesh - The DMPlex 3205 - p - The point, which must lie in the chart set with DMPlexSetChart() 3206 3207 Output Parameter: 3208 . size - The support size for point p 3209 3210 Level: beginner 3211 3212 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3213 @*/ 3214 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3215 { 3216 DM_Plex *mesh = (DM_Plex*) dm->data; 3217 3218 PetscFunctionBegin; 3219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3220 PetscValidIntPointer(size, 3); 3221 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3222 PetscFunctionReturn(0); 3223 } 3224 3225 /*@ 3226 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3227 3228 Not collective 3229 3230 Input Parameters: 3231 + mesh - The DMPlex 3232 . p - The point, which must lie in the chart set with DMPlexSetChart() 3233 - size - The support size for point p 3234 3235 Output Parameter: 3236 3237 Note: 3238 This should be called after DMPlexSetChart(). 3239 3240 Level: beginner 3241 3242 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3243 @*/ 3244 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3245 { 3246 DM_Plex *mesh = (DM_Plex*) dm->data; 3247 3248 PetscFunctionBegin; 3249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3250 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3251 PetscFunctionReturn(0); 3252 } 3253 3254 /*@C 3255 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3256 3257 Not collective 3258 3259 Input Parameters: 3260 + mesh - The DMPlex 3261 - p - The point, which must lie in the chart set with DMPlexSetChart() 3262 3263 Output Parameter: 3264 . support - An array of points which are on the out-edges for point p 3265 3266 Level: beginner 3267 3268 Fortran Notes: 3269 Since it returns an array, this routine is only available in Fortran 90, and you must 3270 include petsc.h90 in your code. 3271 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3272 DMPlexRestoreSupport() is not needed/available in C. 3273 3274 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3275 @*/ 3276 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3277 { 3278 DM_Plex *mesh = (DM_Plex*) dm->data; 3279 PetscInt off; 3280 3281 PetscFunctionBegin; 3282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3283 PetscValidPointer(support, 3); 3284 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3285 *support = &mesh->supports[off]; 3286 PetscFunctionReturn(0); 3287 } 3288 3289 /*@ 3290 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3291 3292 Not collective 3293 3294 Input Parameters: 3295 + mesh - The DMPlex 3296 . p - The point, which must lie in the chart set with DMPlexSetChart() 3297 - support - An array of points which are on the out-edges for point p 3298 3299 Output Parameter: 3300 3301 Note: 3302 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3303 3304 Level: beginner 3305 3306 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3307 @*/ 3308 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3309 { 3310 DM_Plex *mesh = (DM_Plex*) dm->data; 3311 PetscInt pStart, pEnd; 3312 PetscInt dof, off, c; 3313 3314 PetscFunctionBegin; 3315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3316 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3317 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3318 if (dof) PetscValidIntPointer(support, 3); 3319 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3320 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3321 for (c = 0; c < dof; ++c) { 3322 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3323 mesh->supports[off+c] = support[c]; 3324 } 3325 PetscFunctionReturn(0); 3326 } 3327 3328 /*@ 3329 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3330 3331 Not collective 3332 3333 Input Parameters: 3334 + mesh - The DMPlex 3335 . p - The point, which must lie in the chart set with DMPlexSetChart() 3336 . supportPos - The local index in the cone where the point should be put 3337 - supportPoint - The mesh point to insert 3338 3339 Level: beginner 3340 3341 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3342 @*/ 3343 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3344 { 3345 DM_Plex *mesh = (DM_Plex*) dm->data; 3346 PetscInt pStart, pEnd; 3347 PetscInt dof, off; 3348 3349 PetscFunctionBegin; 3350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3351 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3352 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3353 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3354 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3355 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3356 PetscCheck(supportPos < dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3357 mesh->supports[off+supportPos] = supportPoint; 3358 PetscFunctionReturn(0); 3359 } 3360 3361 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3362 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3363 { 3364 switch (ct) { 3365 case DM_POLYTOPE_SEGMENT: 3366 if (o == -1) return -2; 3367 break; 3368 case DM_POLYTOPE_TRIANGLE: 3369 if (o == -3) return -1; 3370 if (o == -2) return -3; 3371 if (o == -1) return -2; 3372 break; 3373 case DM_POLYTOPE_QUADRILATERAL: 3374 if (o == -4) return -2; 3375 if (o == -3) return -1; 3376 if (o == -2) return -4; 3377 if (o == -1) return -3; 3378 break; 3379 default: return o; 3380 } 3381 return o; 3382 } 3383 3384 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3385 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3386 { 3387 switch (ct) { 3388 case DM_POLYTOPE_SEGMENT: 3389 if ((o == -2) || (o == 1)) return -1; 3390 if (o == -1) return 0; 3391 break; 3392 case DM_POLYTOPE_TRIANGLE: 3393 if (o == -3) return -2; 3394 if (o == -2) return -1; 3395 if (o == -1) return -3; 3396 break; 3397 case DM_POLYTOPE_QUADRILATERAL: 3398 if (o == -4) return -2; 3399 if (o == -3) return -1; 3400 if (o == -2) return -4; 3401 if (o == -1) return -3; 3402 break; 3403 default: return o; 3404 } 3405 return o; 3406 } 3407 3408 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3409 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3410 { 3411 PetscInt pStart, pEnd, p; 3412 3413 PetscFunctionBegin; 3414 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3415 for (p = pStart; p < pEnd; ++p) { 3416 const PetscInt *cone, *ornt; 3417 PetscInt coneSize, c; 3418 3419 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3420 PetscCall(DMPlexGetCone(dm, p, &cone)); 3421 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3422 for (c = 0; c < coneSize; ++c) { 3423 DMPolytopeType ct; 3424 const PetscInt o = ornt[c]; 3425 3426 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3427 switch (ct) { 3428 case DM_POLYTOPE_SEGMENT: 3429 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3430 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3431 break; 3432 case DM_POLYTOPE_TRIANGLE: 3433 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3434 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3435 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3436 break; 3437 case DM_POLYTOPE_QUADRILATERAL: 3438 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3439 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3440 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3441 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3442 break; 3443 default: break; 3444 } 3445 } 3446 } 3447 PetscFunctionReturn(0); 3448 } 3449 3450 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3451 { 3452 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3453 PetscInt *closure; 3454 const PetscInt *tmp = NULL, *tmpO = NULL; 3455 PetscInt off = 0, tmpSize, t; 3456 3457 PetscFunctionBeginHot; 3458 if (ornt) { 3459 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3460 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3461 } 3462 if (*points) { 3463 closure = *points; 3464 } else { 3465 PetscInt maxConeSize, maxSupportSize; 3466 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3467 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3468 } 3469 if (useCone) { 3470 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3471 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3472 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3473 } else { 3474 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3475 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3476 } 3477 if (ct == DM_POLYTOPE_UNKNOWN) { 3478 closure[off++] = p; 3479 closure[off++] = 0; 3480 for (t = 0; t < tmpSize; ++t) { 3481 closure[off++] = tmp[t]; 3482 closure[off++] = tmpO ? tmpO[t] : 0; 3483 } 3484 } else { 3485 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3486 3487 /* We assume that cells with a valid type have faces with a valid type */ 3488 closure[off++] = p; 3489 closure[off++] = ornt; 3490 for (t = 0; t < tmpSize; ++t) { 3491 DMPolytopeType ft; 3492 3493 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3494 closure[off++] = tmp[arr[t]]; 3495 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3496 } 3497 } 3498 if (numPoints) *numPoints = tmpSize+1; 3499 if (points) *points = closure; 3500 PetscFunctionReturn(0); 3501 } 3502 3503 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3504 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3505 { 3506 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3507 const PetscInt *cone, *ornt; 3508 PetscInt *pts, *closure = NULL; 3509 DMPolytopeType ft; 3510 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3511 PetscInt dim, coneSize, c, d, clSize, cl; 3512 3513 PetscFunctionBeginHot; 3514 PetscCall(DMGetDimension(dm, &dim)); 3515 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3516 PetscCall(DMPlexGetCone(dm, point, &cone)); 3517 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3518 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3519 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3520 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3521 maxSize = PetscMax(coneSeries, supportSeries); 3522 if (*points) {pts = *points;} 3523 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3524 c = 0; 3525 pts[c++] = point; 3526 pts[c++] = o; 3527 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3528 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3529 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3530 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3531 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3532 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3533 for (d = 2; d < coneSize; ++d) { 3534 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3535 pts[c++] = cone[arr[d*2+0]]; 3536 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3537 } 3538 if (dim >= 3) { 3539 for (d = 2; d < coneSize; ++d) { 3540 const PetscInt fpoint = cone[arr[d*2+0]]; 3541 const PetscInt *fcone, *fornt; 3542 PetscInt fconeSize, fc, i; 3543 3544 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3545 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3546 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3547 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3548 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3549 for (fc = 0; fc < fconeSize; ++fc) { 3550 const PetscInt cp = fcone[farr[fc*2+0]]; 3551 const PetscInt co = farr[fc*2+1]; 3552 3553 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3554 if (i == c) { 3555 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3556 pts[c++] = cp; 3557 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3558 } 3559 } 3560 } 3561 } 3562 *numPoints = c/2; 3563 *points = pts; 3564 PetscFunctionReturn(0); 3565 } 3566 3567 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3568 { 3569 DMPolytopeType ct; 3570 PetscInt *closure, *fifo; 3571 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3572 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3573 PetscInt depth, maxSize; 3574 3575 PetscFunctionBeginHot; 3576 PetscCall(DMPlexGetDepth(dm, &depth)); 3577 if (depth == 1) { 3578 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3579 PetscFunctionReturn(0); 3580 } 3581 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3582 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3583 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3584 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3585 PetscFunctionReturn(0); 3586 } 3587 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3588 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3589 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3590 maxSize = PetscMax(coneSeries, supportSeries); 3591 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3592 if (*points) {closure = *points;} 3593 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3594 closure[closureSize++] = p; 3595 closure[closureSize++] = ornt; 3596 fifo[fifoSize++] = p; 3597 fifo[fifoSize++] = ornt; 3598 fifo[fifoSize++] = ct; 3599 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3600 while (fifoSize - fifoStart) { 3601 const PetscInt q = fifo[fifoStart++]; 3602 const PetscInt o = fifo[fifoStart++]; 3603 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3604 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3605 const PetscInt *tmp, *tmpO; 3606 PetscInt tmpSize, t; 3607 3608 if (PetscDefined(USE_DEBUG)) { 3609 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3610 PetscCheck(!o || !(o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3611 } 3612 if (useCone) { 3613 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3614 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3615 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3616 } else { 3617 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3618 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3619 tmpO = NULL; 3620 } 3621 for (t = 0; t < tmpSize; ++t) { 3622 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3623 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3624 const PetscInt cp = tmp[ip]; 3625 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3626 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3627 PetscInt c; 3628 3629 /* Check for duplicate */ 3630 for (c = 0; c < closureSize; c += 2) { 3631 if (closure[c] == cp) break; 3632 } 3633 if (c == closureSize) { 3634 closure[closureSize++] = cp; 3635 closure[closureSize++] = co; 3636 fifo[fifoSize++] = cp; 3637 fifo[fifoSize++] = co; 3638 fifo[fifoSize++] = ct; 3639 } 3640 } 3641 } 3642 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3643 if (numPoints) *numPoints = closureSize/2; 3644 if (points) *points = closure; 3645 PetscFunctionReturn(0); 3646 } 3647 3648 /*@C 3649 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3650 3651 Not collective 3652 3653 Input Parameters: 3654 + dm - The DMPlex 3655 . p - The mesh point 3656 - useCone - PETSC_TRUE for the closure, otherwise return the star 3657 3658 Input/Output Parameter: 3659 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3660 if NULL on input, internal storage will be returned, otherwise the provided array is used 3661 3662 Output Parameter: 3663 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3664 3665 Note: 3666 If using internal storage (points is NULL on input), each call overwrites the last output. 3667 3668 Fortran Notes: 3669 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3670 3671 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3672 3673 Level: beginner 3674 3675 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3676 @*/ 3677 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3678 { 3679 PetscFunctionBeginHot; 3680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3681 if (numPoints) PetscValidIntPointer(numPoints, 4); 3682 if (points) PetscValidPointer(points, 5); 3683 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3684 PetscFunctionReturn(0); 3685 } 3686 3687 /*@C 3688 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3689 3690 Not collective 3691 3692 Input Parameters: 3693 + dm - The DMPlex 3694 . p - The mesh point 3695 . useCone - PETSC_TRUE for the closure, otherwise return the star 3696 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3697 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3698 3699 Note: 3700 If not using internal storage (points is not NULL on input), this call is unnecessary 3701 3702 Fortran Notes: 3703 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3704 3705 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3706 3707 Level: beginner 3708 3709 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3710 @*/ 3711 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3712 { 3713 PetscFunctionBeginHot; 3714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3715 if (numPoints) *numPoints = 0; 3716 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3717 PetscFunctionReturn(0); 3718 } 3719 3720 /*@ 3721 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3722 3723 Not collective 3724 3725 Input Parameter: 3726 . mesh - The DMPlex 3727 3728 Output Parameters: 3729 + maxConeSize - The maximum number of in-edges 3730 - maxSupportSize - The maximum number of out-edges 3731 3732 Level: beginner 3733 3734 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3735 @*/ 3736 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3737 { 3738 DM_Plex *mesh = (DM_Plex*) dm->data; 3739 3740 PetscFunctionBegin; 3741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3742 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3743 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3744 PetscFunctionReturn(0); 3745 } 3746 3747 PetscErrorCode DMSetUp_Plex(DM dm) 3748 { 3749 DM_Plex *mesh = (DM_Plex*) dm->data; 3750 PetscInt size, maxSupportSize; 3751 3752 PetscFunctionBegin; 3753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3754 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3755 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3756 PetscCall(PetscMalloc1(size, &mesh->cones)); 3757 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3758 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3759 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3760 if (maxSupportSize) { 3761 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3762 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3763 PetscCall(PetscMalloc1(size, &mesh->supports)); 3764 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3765 } 3766 PetscFunctionReturn(0); 3767 } 3768 3769 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3770 { 3771 PetscFunctionBegin; 3772 if (subdm) PetscCall(DMClone(dm, subdm)); 3773 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3774 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3775 if (dm->useNatural && dm->sfMigration) { 3776 PetscSF sfNatural; 3777 3778 (*subdm)->sfMigration = dm->sfMigration; 3779 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3780 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3781 (*subdm)->sfNatural = sfNatural; 3782 } 3783 PetscFunctionReturn(0); 3784 } 3785 3786 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3787 { 3788 PetscInt i = 0; 3789 3790 PetscFunctionBegin; 3791 PetscCall(DMClone(dms[0], superdm)); 3792 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3793 (*superdm)->useNatural = PETSC_FALSE; 3794 for (i = 0; i < len; i++) { 3795 if (dms[i]->useNatural && dms[i]->sfMigration) { 3796 PetscSF sfNatural; 3797 3798 (*superdm)->sfMigration = dms[i]->sfMigration; 3799 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3800 (*superdm)->useNatural = PETSC_TRUE; 3801 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3802 (*superdm)->sfNatural = sfNatural; 3803 break; 3804 } 3805 } 3806 PetscFunctionReturn(0); 3807 } 3808 3809 /*@ 3810 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3811 3812 Not collective 3813 3814 Input Parameter: 3815 . mesh - The DMPlex 3816 3817 Output Parameter: 3818 3819 Note: 3820 This should be called after all calls to DMPlexSetCone() 3821 3822 Level: beginner 3823 3824 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3825 @*/ 3826 PetscErrorCode DMPlexSymmetrize(DM dm) 3827 { 3828 DM_Plex *mesh = (DM_Plex*) dm->data; 3829 PetscInt *offsets; 3830 PetscInt supportSize; 3831 PetscInt pStart, pEnd, p; 3832 3833 PetscFunctionBegin; 3834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3835 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3836 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3837 /* Calculate support sizes */ 3838 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3839 for (p = pStart; p < pEnd; ++p) { 3840 PetscInt dof, off, c; 3841 3842 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3843 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3844 for (c = off; c < off+dof; ++c) { 3845 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3846 } 3847 } 3848 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3849 /* Calculate supports */ 3850 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3851 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3852 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3853 for (p = pStart; p < pEnd; ++p) { 3854 PetscInt dof, off, c; 3855 3856 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3857 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3858 for (c = off; c < off+dof; ++c) { 3859 const PetscInt q = mesh->cones[c]; 3860 PetscInt offS; 3861 3862 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3863 3864 mesh->supports[offS+offsets[q]] = p; 3865 ++offsets[q]; 3866 } 3867 } 3868 PetscCall(PetscFree(offsets)); 3869 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3870 PetscFunctionReturn(0); 3871 } 3872 3873 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3874 { 3875 IS stratumIS; 3876 3877 PetscFunctionBegin; 3878 if (pStart >= pEnd) PetscFunctionReturn(0); 3879 if (PetscDefined(USE_DEBUG)) { 3880 PetscInt qStart, qEnd, numLevels, level; 3881 PetscBool overlap = PETSC_FALSE; 3882 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3883 for (level = 0; level < numLevels; level++) { 3884 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3885 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3886 } 3887 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); 3888 } 3889 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3890 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3891 PetscCall(ISDestroy(&stratumIS)); 3892 PetscFunctionReturn(0); 3893 } 3894 3895 /*@ 3896 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3897 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3898 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3899 the DAG. 3900 3901 Collective on dm 3902 3903 Input Parameter: 3904 . mesh - The DMPlex 3905 3906 Output Parameter: 3907 3908 Notes: 3909 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3910 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3911 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3912 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3913 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3914 3915 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3916 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3917 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 3918 to interpolate only that one (e0), so that 3919 $ cone(c0) = {e0, v2} 3920 $ cone(e0) = {v0, v1} 3921 If DMPlexStratify() is run on this mesh, it will give depths 3922 $ depth 0 = {v0, v1, v2} 3923 $ depth 1 = {e0, c0} 3924 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3925 3926 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3927 3928 Level: beginner 3929 3930 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3931 @*/ 3932 PetscErrorCode DMPlexStratify(DM dm) 3933 { 3934 DM_Plex *mesh = (DM_Plex*) dm->data; 3935 DMLabel label; 3936 PetscInt pStart, pEnd, p; 3937 PetscInt numRoots = 0, numLeaves = 0; 3938 3939 PetscFunctionBegin; 3940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3941 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3942 3943 /* Create depth label */ 3944 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3945 PetscCall(DMCreateLabel(dm, "depth")); 3946 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3947 3948 { 3949 /* Initialize roots and count leaves */ 3950 PetscInt sMin = PETSC_MAX_INT; 3951 PetscInt sMax = PETSC_MIN_INT; 3952 PetscInt coneSize, supportSize; 3953 3954 for (p = pStart; p < pEnd; ++p) { 3955 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3956 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3957 if (!coneSize && supportSize) { 3958 sMin = PetscMin(p, sMin); 3959 sMax = PetscMax(p, sMax); 3960 ++numRoots; 3961 } else if (!supportSize && coneSize) { 3962 ++numLeaves; 3963 } else if (!supportSize && !coneSize) { 3964 /* Isolated points */ 3965 sMin = PetscMin(p, sMin); 3966 sMax = PetscMax(p, sMax); 3967 } 3968 } 3969 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3970 } 3971 3972 if (numRoots + numLeaves == (pEnd - pStart)) { 3973 PetscInt sMin = PETSC_MAX_INT; 3974 PetscInt sMax = PETSC_MIN_INT; 3975 PetscInt coneSize, supportSize; 3976 3977 for (p = pStart; p < pEnd; ++p) { 3978 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3979 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3980 if (!supportSize && coneSize) { 3981 sMin = PetscMin(p, sMin); 3982 sMax = PetscMax(p, sMax); 3983 } 3984 } 3985 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3986 } else { 3987 PetscInt level = 0; 3988 PetscInt qStart, qEnd, q; 3989 3990 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3991 while (qEnd > qStart) { 3992 PetscInt sMin = PETSC_MAX_INT; 3993 PetscInt sMax = PETSC_MIN_INT; 3994 3995 for (q = qStart; q < qEnd; ++q) { 3996 const PetscInt *support; 3997 PetscInt supportSize, s; 3998 3999 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4000 PetscCall(DMPlexGetSupport(dm, q, &support)); 4001 for (s = 0; s < supportSize; ++s) { 4002 sMin = PetscMin(support[s], sMin); 4003 sMax = PetscMax(support[s], sMax); 4004 } 4005 } 4006 PetscCall(DMLabelGetNumValues(label, &level)); 4007 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4008 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4009 } 4010 } 4011 { /* just in case there is an empty process */ 4012 PetscInt numValues, maxValues = 0, v; 4013 4014 PetscCall(DMLabelGetNumValues(label, &numValues)); 4015 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4016 for (v = numValues; v < maxValues; v++) { 4017 PetscCall(DMLabelAddStratum(label, v)); 4018 } 4019 } 4020 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4021 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4022 PetscFunctionReturn(0); 4023 } 4024 4025 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4026 { 4027 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4028 PetscInt dim, depth, pheight, coneSize; 4029 4030 PetscFunctionBeginHot; 4031 PetscCall(DMGetDimension(dm, &dim)); 4032 PetscCall(DMPlexGetDepth(dm, &depth)); 4033 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4034 pheight = depth - pdepth; 4035 if (depth <= 1) { 4036 switch (pdepth) { 4037 case 0: ct = DM_POLYTOPE_POINT;break; 4038 case 1: 4039 switch (coneSize) { 4040 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4041 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4042 case 4: 4043 switch (dim) { 4044 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4045 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4046 default: break; 4047 } 4048 break; 4049 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4050 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4051 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4052 default: break; 4053 } 4054 } 4055 } else { 4056 if (pdepth == 0) { 4057 ct = DM_POLYTOPE_POINT; 4058 } else if (pheight == 0) { 4059 switch (dim) { 4060 case 1: 4061 switch (coneSize) { 4062 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4063 default: break; 4064 } 4065 break; 4066 case 2: 4067 switch (coneSize) { 4068 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4069 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4070 default: break; 4071 } 4072 break; 4073 case 3: 4074 switch (coneSize) { 4075 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4076 case 5: 4077 { 4078 const PetscInt *cone; 4079 PetscInt faceConeSize; 4080 4081 PetscCall(DMPlexGetCone(dm, p, &cone)); 4082 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4083 switch (faceConeSize) { 4084 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4085 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4086 } 4087 } 4088 break; 4089 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4090 default: break; 4091 } 4092 break; 4093 default: break; 4094 } 4095 } else if (pheight > 0) { 4096 switch (coneSize) { 4097 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4098 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4099 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4100 default: break; 4101 } 4102 } 4103 } 4104 *pt = ct; 4105 PetscFunctionReturn(0); 4106 } 4107 4108 /*@ 4109 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4110 4111 Collective on dm 4112 4113 Input Parameter: 4114 . mesh - The DMPlex 4115 4116 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4117 4118 Level: developer 4119 4120 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4121 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4122 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4123 4124 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4125 @*/ 4126 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4127 { 4128 DM_Plex *mesh; 4129 DMLabel ctLabel; 4130 PetscInt pStart, pEnd, p; 4131 4132 PetscFunctionBegin; 4133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4134 mesh = (DM_Plex *) dm->data; 4135 PetscCall(DMCreateLabel(dm, "celltype")); 4136 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4137 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4138 for (p = pStart; p < pEnd; ++p) { 4139 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4140 PetscInt pdepth; 4141 4142 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4143 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4144 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4145 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4146 } 4147 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4148 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4149 PetscFunctionReturn(0); 4150 } 4151 4152 /*@C 4153 DMPlexGetJoin - Get an array for the join of the set of points 4154 4155 Not Collective 4156 4157 Input Parameters: 4158 + dm - The DMPlex object 4159 . numPoints - The number of input points for the join 4160 - points - The input points 4161 4162 Output Parameters: 4163 + numCoveredPoints - The number of points in the join 4164 - coveredPoints - The points in the join 4165 4166 Level: intermediate 4167 4168 Note: Currently, this is restricted to a single level join 4169 4170 Fortran Notes: 4171 Since it returns an array, this routine is only available in Fortran 90, and you must 4172 include petsc.h90 in your code. 4173 4174 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4175 4176 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4177 @*/ 4178 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4179 { 4180 DM_Plex *mesh = (DM_Plex*) dm->data; 4181 PetscInt *join[2]; 4182 PetscInt joinSize, i = 0; 4183 PetscInt dof, off, p, c, m; 4184 PetscInt maxSupportSize; 4185 4186 PetscFunctionBegin; 4187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4188 PetscValidIntPointer(points, 3); 4189 PetscValidIntPointer(numCoveredPoints, 4); 4190 PetscValidPointer(coveredPoints, 5); 4191 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4192 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4193 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4194 /* Copy in support of first point */ 4195 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4196 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4197 for (joinSize = 0; joinSize < dof; ++joinSize) { 4198 join[i][joinSize] = mesh->supports[off+joinSize]; 4199 } 4200 /* Check each successive support */ 4201 for (p = 1; p < numPoints; ++p) { 4202 PetscInt newJoinSize = 0; 4203 4204 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4205 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4206 for (c = 0; c < dof; ++c) { 4207 const PetscInt point = mesh->supports[off+c]; 4208 4209 for (m = 0; m < joinSize; ++m) { 4210 if (point == join[i][m]) { 4211 join[1-i][newJoinSize++] = point; 4212 break; 4213 } 4214 } 4215 } 4216 joinSize = newJoinSize; 4217 i = 1-i; 4218 } 4219 *numCoveredPoints = joinSize; 4220 *coveredPoints = join[i]; 4221 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4222 PetscFunctionReturn(0); 4223 } 4224 4225 /*@C 4226 DMPlexRestoreJoin - Restore an array for the join of the set of points 4227 4228 Not Collective 4229 4230 Input Parameters: 4231 + dm - The DMPlex object 4232 . numPoints - The number of input points for the join 4233 - points - The input points 4234 4235 Output Parameters: 4236 + numCoveredPoints - The number of points in the join 4237 - coveredPoints - The points in the join 4238 4239 Fortran Notes: 4240 Since it returns an array, this routine is only available in Fortran 90, and you must 4241 include petsc.h90 in your code. 4242 4243 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4244 4245 Level: intermediate 4246 4247 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4248 @*/ 4249 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4250 { 4251 PetscFunctionBegin; 4252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4253 if (points) PetscValidIntPointer(points,3); 4254 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4255 PetscValidPointer(coveredPoints, 5); 4256 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4257 if (numCoveredPoints) *numCoveredPoints = 0; 4258 PetscFunctionReturn(0); 4259 } 4260 4261 /*@C 4262 DMPlexGetFullJoin - Get an array for the join of the set of points 4263 4264 Not Collective 4265 4266 Input Parameters: 4267 + dm - The DMPlex object 4268 . numPoints - The number of input points for the join 4269 - points - The input points 4270 4271 Output Parameters: 4272 + numCoveredPoints - The number of points in the join 4273 - coveredPoints - The points in the join 4274 4275 Fortran Notes: 4276 Since it returns an array, this routine is only available in Fortran 90, and you must 4277 include petsc.h90 in your code. 4278 4279 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4280 4281 Level: intermediate 4282 4283 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4284 @*/ 4285 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4286 { 4287 PetscInt *offsets, **closures; 4288 PetscInt *join[2]; 4289 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4290 PetscInt p, d, c, m, ms; 4291 4292 PetscFunctionBegin; 4293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4294 PetscValidIntPointer(points, 3); 4295 PetscValidIntPointer(numCoveredPoints, 4); 4296 PetscValidPointer(coveredPoints, 5); 4297 4298 PetscCall(DMPlexGetDepth(dm, &depth)); 4299 PetscCall(PetscCalloc1(numPoints, &closures)); 4300 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4301 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4302 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4303 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4304 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4305 4306 for (p = 0; p < numPoints; ++p) { 4307 PetscInt closureSize; 4308 4309 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4310 4311 offsets[p*(depth+2)+0] = 0; 4312 for (d = 0; d < depth+1; ++d) { 4313 PetscInt pStart, pEnd, i; 4314 4315 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4316 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4317 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4318 offsets[p*(depth+2)+d+1] = i; 4319 break; 4320 } 4321 } 4322 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4323 } 4324 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); 4325 } 4326 for (d = 0; d < depth+1; ++d) { 4327 PetscInt dof; 4328 4329 /* Copy in support of first point */ 4330 dof = offsets[d+1] - offsets[d]; 4331 for (joinSize = 0; joinSize < dof; ++joinSize) { 4332 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4333 } 4334 /* Check each successive cone */ 4335 for (p = 1; p < numPoints && joinSize; ++p) { 4336 PetscInt newJoinSize = 0; 4337 4338 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4339 for (c = 0; c < dof; ++c) { 4340 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4341 4342 for (m = 0; m < joinSize; ++m) { 4343 if (point == join[i][m]) { 4344 join[1-i][newJoinSize++] = point; 4345 break; 4346 } 4347 } 4348 } 4349 joinSize = newJoinSize; 4350 i = 1-i; 4351 } 4352 if (joinSize) break; 4353 } 4354 *numCoveredPoints = joinSize; 4355 *coveredPoints = join[i]; 4356 for (p = 0; p < numPoints; ++p) { 4357 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4358 } 4359 PetscCall(PetscFree(closures)); 4360 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4361 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4362 PetscFunctionReturn(0); 4363 } 4364 4365 /*@C 4366 DMPlexGetMeet - Get an array for the meet of the set of points 4367 4368 Not Collective 4369 4370 Input Parameters: 4371 + dm - The DMPlex object 4372 . numPoints - The number of input points for the meet 4373 - points - The input points 4374 4375 Output Parameters: 4376 + numCoveredPoints - The number of points in the meet 4377 - coveredPoints - The points in the meet 4378 4379 Level: intermediate 4380 4381 Note: Currently, this is restricted to a single level meet 4382 4383 Fortran Notes: 4384 Since it returns an array, this routine is only available in Fortran 90, and you must 4385 include petsc.h90 in your code. 4386 4387 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4388 4389 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4390 @*/ 4391 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4392 { 4393 DM_Plex *mesh = (DM_Plex*) dm->data; 4394 PetscInt *meet[2]; 4395 PetscInt meetSize, i = 0; 4396 PetscInt dof, off, p, c, m; 4397 PetscInt maxConeSize; 4398 4399 PetscFunctionBegin; 4400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4401 PetscValidIntPointer(points, 3); 4402 PetscValidIntPointer(numCoveringPoints, 4); 4403 PetscValidPointer(coveringPoints, 5); 4404 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4405 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4406 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4407 /* Copy in cone of first point */ 4408 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4409 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4410 for (meetSize = 0; meetSize < dof; ++meetSize) { 4411 meet[i][meetSize] = mesh->cones[off+meetSize]; 4412 } 4413 /* Check each successive cone */ 4414 for (p = 1; p < numPoints; ++p) { 4415 PetscInt newMeetSize = 0; 4416 4417 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4418 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4419 for (c = 0; c < dof; ++c) { 4420 const PetscInt point = mesh->cones[off+c]; 4421 4422 for (m = 0; m < meetSize; ++m) { 4423 if (point == meet[i][m]) { 4424 meet[1-i][newMeetSize++] = point; 4425 break; 4426 } 4427 } 4428 } 4429 meetSize = newMeetSize; 4430 i = 1-i; 4431 } 4432 *numCoveringPoints = meetSize; 4433 *coveringPoints = meet[i]; 4434 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4435 PetscFunctionReturn(0); 4436 } 4437 4438 /*@C 4439 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4440 4441 Not Collective 4442 4443 Input Parameters: 4444 + dm - The DMPlex object 4445 . numPoints - The number of input points for the meet 4446 - points - The input points 4447 4448 Output Parameters: 4449 + numCoveredPoints - The number of points in the meet 4450 - coveredPoints - The points in the meet 4451 4452 Level: intermediate 4453 4454 Fortran Notes: 4455 Since it returns an array, this routine is only available in Fortran 90, and you must 4456 include petsc.h90 in your code. 4457 4458 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4459 4460 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4461 @*/ 4462 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4463 { 4464 PetscFunctionBegin; 4465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4466 if (points) PetscValidIntPointer(points,3); 4467 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4468 PetscValidPointer(coveredPoints,5); 4469 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4470 if (numCoveredPoints) *numCoveredPoints = 0; 4471 PetscFunctionReturn(0); 4472 } 4473 4474 /*@C 4475 DMPlexGetFullMeet - Get an array for the meet of the set of points 4476 4477 Not Collective 4478 4479 Input Parameters: 4480 + dm - The DMPlex object 4481 . numPoints - The number of input points for the meet 4482 - points - The input points 4483 4484 Output Parameters: 4485 + numCoveredPoints - The number of points in the meet 4486 - coveredPoints - The points in the meet 4487 4488 Level: intermediate 4489 4490 Fortran Notes: 4491 Since it returns an array, this routine is only available in Fortran 90, and you must 4492 include petsc.h90 in your code. 4493 4494 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4495 4496 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4497 @*/ 4498 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4499 { 4500 PetscInt *offsets, **closures; 4501 PetscInt *meet[2]; 4502 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4503 PetscInt p, h, c, m, mc; 4504 4505 PetscFunctionBegin; 4506 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4507 PetscValidIntPointer(points, 3); 4508 PetscValidIntPointer(numCoveredPoints, 4); 4509 PetscValidPointer(coveredPoints, 5); 4510 4511 PetscCall(DMPlexGetDepth(dm, &height)); 4512 PetscCall(PetscMalloc1(numPoints, &closures)); 4513 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4514 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4515 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4516 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4517 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4518 4519 for (p = 0; p < numPoints; ++p) { 4520 PetscInt closureSize; 4521 4522 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4523 4524 offsets[p*(height+2)+0] = 0; 4525 for (h = 0; h < height+1; ++h) { 4526 PetscInt pStart, pEnd, i; 4527 4528 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4529 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4530 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4531 offsets[p*(height+2)+h+1] = i; 4532 break; 4533 } 4534 } 4535 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4536 } 4537 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); 4538 } 4539 for (h = 0; h < height+1; ++h) { 4540 PetscInt dof; 4541 4542 /* Copy in cone of first point */ 4543 dof = offsets[h+1] - offsets[h]; 4544 for (meetSize = 0; meetSize < dof; ++meetSize) { 4545 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4546 } 4547 /* Check each successive cone */ 4548 for (p = 1; p < numPoints && meetSize; ++p) { 4549 PetscInt newMeetSize = 0; 4550 4551 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4552 for (c = 0; c < dof; ++c) { 4553 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4554 4555 for (m = 0; m < meetSize; ++m) { 4556 if (point == meet[i][m]) { 4557 meet[1-i][newMeetSize++] = point; 4558 break; 4559 } 4560 } 4561 } 4562 meetSize = newMeetSize; 4563 i = 1-i; 4564 } 4565 if (meetSize) break; 4566 } 4567 *numCoveredPoints = meetSize; 4568 *coveredPoints = meet[i]; 4569 for (p = 0; p < numPoints; ++p) { 4570 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4571 } 4572 PetscCall(PetscFree(closures)); 4573 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4574 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4575 PetscFunctionReturn(0); 4576 } 4577 4578 /*@C 4579 DMPlexEqual - Determine if two DMs have the same topology 4580 4581 Not Collective 4582 4583 Input Parameters: 4584 + dmA - A DMPlex object 4585 - dmB - A DMPlex object 4586 4587 Output Parameters: 4588 . equal - PETSC_TRUE if the topologies are identical 4589 4590 Level: intermediate 4591 4592 Notes: 4593 We are not solving graph isomorphism, so we do not permutation. 4594 4595 .seealso: `DMPlexGetCone()` 4596 @*/ 4597 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4598 { 4599 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4600 4601 PetscFunctionBegin; 4602 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4603 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4604 PetscValidBoolPointer(equal, 3); 4605 4606 *equal = PETSC_FALSE; 4607 PetscCall(DMPlexGetDepth(dmA, &depth)); 4608 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4609 if (depth != depthB) PetscFunctionReturn(0); 4610 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4611 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4612 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4613 for (p = pStart; p < pEnd; ++p) { 4614 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4615 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4616 4617 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4618 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4619 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4620 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4621 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4622 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4623 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4624 for (c = 0; c < coneSize; ++c) { 4625 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4626 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4627 } 4628 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4629 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4630 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4631 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4632 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4633 for (s = 0; s < supportSize; ++s) { 4634 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4635 } 4636 } 4637 *equal = PETSC_TRUE; 4638 PetscFunctionReturn(0); 4639 } 4640 4641 /*@C 4642 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4643 4644 Not Collective 4645 4646 Input Parameters: 4647 + dm - The DMPlex 4648 . cellDim - The cell dimension 4649 - numCorners - The number of vertices on a cell 4650 4651 Output Parameters: 4652 . numFaceVertices - The number of vertices on a face 4653 4654 Level: developer 4655 4656 Notes: 4657 Of course this can only work for a restricted set of symmetric shapes 4658 4659 .seealso: `DMPlexGetCone()` 4660 @*/ 4661 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4662 { 4663 MPI_Comm comm; 4664 4665 PetscFunctionBegin; 4666 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4667 PetscValidIntPointer(numFaceVertices,4); 4668 switch (cellDim) { 4669 case 0: 4670 *numFaceVertices = 0; 4671 break; 4672 case 1: 4673 *numFaceVertices = 1; 4674 break; 4675 case 2: 4676 switch (numCorners) { 4677 case 3: /* triangle */ 4678 *numFaceVertices = 2; /* Edge has 2 vertices */ 4679 break; 4680 case 4: /* quadrilateral */ 4681 *numFaceVertices = 2; /* Edge has 2 vertices */ 4682 break; 4683 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4684 *numFaceVertices = 3; /* Edge has 3 vertices */ 4685 break; 4686 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4687 *numFaceVertices = 3; /* Edge has 3 vertices */ 4688 break; 4689 default: 4690 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4691 } 4692 break; 4693 case 3: 4694 switch (numCorners) { 4695 case 4: /* tetradehdron */ 4696 *numFaceVertices = 3; /* Face has 3 vertices */ 4697 break; 4698 case 6: /* tet cohesive cells */ 4699 *numFaceVertices = 4; /* Face has 4 vertices */ 4700 break; 4701 case 8: /* hexahedron */ 4702 *numFaceVertices = 4; /* Face has 4 vertices */ 4703 break; 4704 case 9: /* tet cohesive Lagrange cells */ 4705 *numFaceVertices = 6; /* Face has 6 vertices */ 4706 break; 4707 case 10: /* quadratic tetrahedron */ 4708 *numFaceVertices = 6; /* Face has 6 vertices */ 4709 break; 4710 case 12: /* hex cohesive Lagrange cells */ 4711 *numFaceVertices = 6; /* Face has 6 vertices */ 4712 break; 4713 case 18: /* quadratic tet cohesive Lagrange cells */ 4714 *numFaceVertices = 6; /* Face has 6 vertices */ 4715 break; 4716 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4717 *numFaceVertices = 9; /* Face has 9 vertices */ 4718 break; 4719 default: 4720 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4721 } 4722 break; 4723 default: 4724 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4725 } 4726 PetscFunctionReturn(0); 4727 } 4728 4729 /*@ 4730 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4731 4732 Not Collective 4733 4734 Input Parameter: 4735 . dm - The DMPlex object 4736 4737 Output Parameter: 4738 . depthLabel - The DMLabel recording point depth 4739 4740 Level: developer 4741 4742 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4743 @*/ 4744 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4745 { 4746 PetscFunctionBegin; 4747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4748 PetscValidPointer(depthLabel, 2); 4749 *depthLabel = dm->depthLabel; 4750 PetscFunctionReturn(0); 4751 } 4752 4753 /*@ 4754 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4755 4756 Not Collective 4757 4758 Input Parameter: 4759 . dm - The DMPlex object 4760 4761 Output Parameter: 4762 . depth - The number of strata (breadth first levels) in the DAG 4763 4764 Level: developer 4765 4766 Notes: 4767 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4768 The point depth is described more in detail in DMPlexGetDepthStratum(). 4769 An empty mesh gives -1. 4770 4771 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4772 @*/ 4773 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4774 { 4775 DMLabel label; 4776 PetscInt d = 0; 4777 4778 PetscFunctionBegin; 4779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4780 PetscValidIntPointer(depth, 2); 4781 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4782 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4783 *depth = d-1; 4784 PetscFunctionReturn(0); 4785 } 4786 4787 /*@ 4788 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4789 4790 Not Collective 4791 4792 Input Parameters: 4793 + dm - The DMPlex object 4794 - depth - The requested depth 4795 4796 Output Parameters: 4797 + start - The first point at this depth 4798 - end - One beyond the last point at this depth 4799 4800 Notes: 4801 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4802 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4803 higher dimension, e.g., "edges". 4804 4805 Level: developer 4806 4807 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4808 @*/ 4809 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4810 { 4811 DMLabel label; 4812 PetscInt pStart, pEnd; 4813 4814 PetscFunctionBegin; 4815 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4816 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4817 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4818 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4819 if (pStart == pEnd) PetscFunctionReturn(0); 4820 if (depth < 0) { 4821 if (start) *start = pStart; 4822 if (end) *end = pEnd; 4823 PetscFunctionReturn(0); 4824 } 4825 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4826 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4827 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4828 PetscFunctionReturn(0); 4829 } 4830 4831 /*@ 4832 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4833 4834 Not Collective 4835 4836 Input Parameters: 4837 + dm - The DMPlex object 4838 - height - The requested height 4839 4840 Output Parameters: 4841 + start - The first point at this height 4842 - end - One beyond the last point at this height 4843 4844 Notes: 4845 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4846 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4847 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4848 4849 Level: developer 4850 4851 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4852 @*/ 4853 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4854 { 4855 DMLabel label; 4856 PetscInt depth, pStart, pEnd; 4857 4858 PetscFunctionBegin; 4859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4860 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4861 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4862 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4863 if (pStart == pEnd) PetscFunctionReturn(0); 4864 if (height < 0) { 4865 if (start) *start = pStart; 4866 if (end) *end = pEnd; 4867 PetscFunctionReturn(0); 4868 } 4869 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4870 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4871 PetscCall(DMLabelGetNumValues(label, &depth)); 4872 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4873 PetscFunctionReturn(0); 4874 } 4875 4876 /*@ 4877 DMPlexGetPointDepth - Get the depth of a given point 4878 4879 Not Collective 4880 4881 Input Parameters: 4882 + dm - The DMPlex object 4883 - point - The point 4884 4885 Output Parameter: 4886 . depth - The depth of the point 4887 4888 Level: intermediate 4889 4890 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4891 @*/ 4892 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4893 { 4894 PetscFunctionBegin; 4895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4896 PetscValidIntPointer(depth, 3); 4897 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4898 PetscFunctionReturn(0); 4899 } 4900 4901 /*@ 4902 DMPlexGetPointHeight - Get the height of a given point 4903 4904 Not Collective 4905 4906 Input Parameters: 4907 + dm - The DMPlex object 4908 - point - The point 4909 4910 Output Parameter: 4911 . height - The height of the point 4912 4913 Level: intermediate 4914 4915 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4916 @*/ 4917 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4918 { 4919 PetscInt n, pDepth; 4920 4921 PetscFunctionBegin; 4922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4923 PetscValidIntPointer(height, 3); 4924 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4925 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4926 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4927 PetscFunctionReturn(0); 4928 } 4929 4930 /*@ 4931 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4932 4933 Not Collective 4934 4935 Input Parameter: 4936 . dm - The DMPlex object 4937 4938 Output Parameter: 4939 . celltypeLabel - The DMLabel recording cell polytope type 4940 4941 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4942 DMCreateLabel(dm, "celltype") beforehand. 4943 4944 Level: developer 4945 4946 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4947 @*/ 4948 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4949 { 4950 PetscFunctionBegin; 4951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4952 PetscValidPointer(celltypeLabel, 2); 4953 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4954 *celltypeLabel = dm->celltypeLabel; 4955 PetscFunctionReturn(0); 4956 } 4957 4958 /*@ 4959 DMPlexGetCellType - Get the polytope type of a given cell 4960 4961 Not Collective 4962 4963 Input Parameters: 4964 + dm - The DMPlex object 4965 - cell - The cell 4966 4967 Output Parameter: 4968 . celltype - The polytope type of the cell 4969 4970 Level: intermediate 4971 4972 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4973 @*/ 4974 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4975 { 4976 DMLabel label; 4977 PetscInt ct; 4978 4979 PetscFunctionBegin; 4980 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4981 PetscValidPointer(celltype, 3); 4982 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4983 PetscCall(DMLabelGetValue(label, cell, &ct)); 4984 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4985 *celltype = (DMPolytopeType) ct; 4986 PetscFunctionReturn(0); 4987 } 4988 4989 /*@ 4990 DMPlexSetCellType - Set the polytope type of a given cell 4991 4992 Not Collective 4993 4994 Input Parameters: 4995 + dm - The DMPlex object 4996 . cell - The cell 4997 - celltype - The polytope type of the cell 4998 4999 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5000 is executed. This function will override the computed type. However, if automatic classification will not succeed 5001 and a user wants to manually specify all types, the classification must be disabled by calling 5002 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5003 5004 Level: advanced 5005 5006 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5007 @*/ 5008 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5009 { 5010 DMLabel label; 5011 5012 PetscFunctionBegin; 5013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5014 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5015 PetscCall(DMLabelSetValue(label, cell, celltype)); 5016 PetscFunctionReturn(0); 5017 } 5018 5019 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5020 { 5021 PetscSection section, s; 5022 Mat m; 5023 PetscInt maxHeight; 5024 5025 PetscFunctionBegin; 5026 PetscCall(DMClone(dm, cdm)); 5027 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5028 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5029 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5030 PetscCall(DMSetLocalSection(*cdm, section)); 5031 PetscCall(PetscSectionDestroy(§ion)); 5032 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5033 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5034 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5035 PetscCall(PetscSectionDestroy(&s)); 5036 PetscCall(MatDestroy(&m)); 5037 5038 PetscCall(DMSetNumFields(*cdm, 1)); 5039 PetscCall(DMCreateDS(*cdm)); 5040 PetscFunctionReturn(0); 5041 } 5042 5043 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5044 { 5045 Vec coordsLocal, cellCoordsLocal; 5046 DM coordsDM, cellCoordsDM; 5047 5048 PetscFunctionBegin; 5049 *field = NULL; 5050 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5051 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5052 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5053 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5054 if (coordsLocal && coordsDM) { 5055 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5056 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5057 } 5058 PetscFunctionReturn(0); 5059 } 5060 5061 /*@C 5062 DMPlexGetConeSection - Return a section which describes the layout of cone data 5063 5064 Not Collective 5065 5066 Input Parameters: 5067 . dm - The DMPlex object 5068 5069 Output Parameter: 5070 . section - The PetscSection object 5071 5072 Level: developer 5073 5074 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5075 @*/ 5076 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5077 { 5078 DM_Plex *mesh = (DM_Plex*) dm->data; 5079 5080 PetscFunctionBegin; 5081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5082 if (section) *section = mesh->coneSection; 5083 PetscFunctionReturn(0); 5084 } 5085 5086 /*@C 5087 DMPlexGetSupportSection - Return a section which describes the layout of support data 5088 5089 Not Collective 5090 5091 Input Parameters: 5092 . dm - The DMPlex object 5093 5094 Output Parameter: 5095 . section - The PetscSection object 5096 5097 Level: developer 5098 5099 .seealso: `DMPlexGetConeSection()` 5100 @*/ 5101 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5102 { 5103 DM_Plex *mesh = (DM_Plex*) dm->data; 5104 5105 PetscFunctionBegin; 5106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5107 if (section) *section = mesh->supportSection; 5108 PetscFunctionReturn(0); 5109 } 5110 5111 /*@C 5112 DMPlexGetCones - Return cone data 5113 5114 Not Collective 5115 5116 Input Parameters: 5117 . dm - The DMPlex object 5118 5119 Output Parameter: 5120 . cones - The cone for each point 5121 5122 Level: developer 5123 5124 .seealso: `DMPlexGetConeSection()` 5125 @*/ 5126 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5127 { 5128 DM_Plex *mesh = (DM_Plex*) dm->data; 5129 5130 PetscFunctionBegin; 5131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5132 if (cones) *cones = mesh->cones; 5133 PetscFunctionReturn(0); 5134 } 5135 5136 /*@C 5137 DMPlexGetConeOrientations - Return cone orientation data 5138 5139 Not Collective 5140 5141 Input Parameters: 5142 . dm - The DMPlex object 5143 5144 Output Parameter: 5145 . coneOrientations - The array of cone orientations for all points 5146 5147 Level: developer 5148 5149 Notes: 5150 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5151 5152 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5153 5154 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5155 @*/ 5156 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5157 { 5158 DM_Plex *mesh = (DM_Plex*) dm->data; 5159 5160 PetscFunctionBegin; 5161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5162 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5163 PetscFunctionReturn(0); 5164 } 5165 5166 /******************************** FEM Support **********************************/ 5167 5168 /* 5169 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5170 representing a line in the section. 5171 */ 5172 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5173 { 5174 PetscFunctionBeginHot; 5175 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5176 if (line < 0) { 5177 *k = 0; 5178 *Nc = 0; 5179 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5180 *k = 1; 5181 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5182 /* An order k SEM disc has k-1 dofs on an edge */ 5183 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5184 *k = *k / *Nc + 1; 5185 } 5186 PetscFunctionReturn(0); 5187 } 5188 5189 /*@ 5190 5191 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5192 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5193 section provided (or the section of the DM). 5194 5195 Input Parameters: 5196 + dm - The DM 5197 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5198 - section - The PetscSection to reorder, or NULL for the default section 5199 5200 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5201 degree of the basis. 5202 5203 Example: 5204 A typical interpolated single-quad mesh might order points as 5205 .vb 5206 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5207 5208 v4 -- e6 -- v3 5209 | | 5210 e7 c0 e8 5211 | | 5212 v1 -- e5 -- v2 5213 .ve 5214 5215 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5216 dofs in the order of points, e.g., 5217 .vb 5218 c0 -> [0,1,2,3] 5219 v1 -> [4] 5220 ... 5221 e5 -> [8, 9] 5222 .ve 5223 5224 which corresponds to the dofs 5225 .vb 5226 6 10 11 7 5227 13 2 3 15 5228 12 0 1 14 5229 4 8 9 5 5230 .ve 5231 5232 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5233 .vb 5234 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5235 .ve 5236 5237 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5238 .vb 5239 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5240 .ve 5241 5242 Level: developer 5243 5244 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5245 @*/ 5246 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5247 { 5248 DMLabel label; 5249 PetscInt dim, depth = -1, eStart = -1, Nf; 5250 PetscBool vertexchart; 5251 5252 PetscFunctionBegin; 5253 PetscCall(DMGetDimension(dm, &dim)); 5254 if (dim < 1) PetscFunctionReturn(0); 5255 if (point < 0) { 5256 PetscInt sStart,sEnd; 5257 5258 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5259 point = sEnd-sStart ? sStart : point; 5260 } 5261 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5262 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5263 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5264 if (depth == 1) {eStart = point;} 5265 else if (depth == dim) { 5266 const PetscInt *cone; 5267 5268 PetscCall(DMPlexGetCone(dm, point, &cone)); 5269 if (dim == 2) eStart = cone[0]; 5270 else if (dim == 3) { 5271 const PetscInt *cone2; 5272 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5273 eStart = cone2[0]; 5274 } 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); 5275 } 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); 5276 { /* Determine whether the chart covers all points or just vertices. */ 5277 PetscInt pStart,pEnd,cStart,cEnd; 5278 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5279 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5280 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5281 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5282 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5283 } 5284 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5285 for (PetscInt d=1; d<=dim; d++) { 5286 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5287 PetscInt *perm; 5288 5289 for (f = 0; f < Nf; ++f) { 5290 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5291 size += PetscPowInt(k+1, d)*Nc; 5292 } 5293 PetscCall(PetscMalloc1(size, &perm)); 5294 for (f = 0; f < Nf; ++f) { 5295 switch (d) { 5296 case 1: 5297 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5298 /* 5299 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5300 We want [ vtx0; edge of length k-1; vtx1 ] 5301 */ 5302 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5303 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5304 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5305 foffset = offset; 5306 break; 5307 case 2: 5308 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5309 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5310 /* The SEM order is 5311 5312 v_lb, {e_b}, v_rb, 5313 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5314 v_lt, reverse {e_t}, v_rt 5315 */ 5316 { 5317 const PetscInt of = 0; 5318 const PetscInt oeb = of + PetscSqr(k-1); 5319 const PetscInt oer = oeb + (k-1); 5320 const PetscInt oet = oer + (k-1); 5321 const PetscInt oel = oet + (k-1); 5322 const PetscInt ovlb = oel + (k-1); 5323 const PetscInt ovrb = ovlb + 1; 5324 const PetscInt ovrt = ovrb + 1; 5325 const PetscInt ovlt = ovrt + 1; 5326 PetscInt o; 5327 5328 /* bottom */ 5329 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5330 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5331 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5332 /* middle */ 5333 for (i = 0; i < k-1; ++i) { 5334 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5335 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; 5336 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5337 } 5338 /* top */ 5339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5340 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5341 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5342 foffset = offset; 5343 } 5344 break; 5345 case 3: 5346 /* The original hex closure is 5347 5348 {c, 5349 f_b, f_t, f_f, f_b, f_r, f_l, 5350 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5351 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5352 */ 5353 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5354 /* The SEM order is 5355 Bottom Slice 5356 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5357 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5358 v_blb, {e_bb}, v_brb, 5359 5360 Middle Slice (j) 5361 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5362 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5363 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5364 5365 Top Slice 5366 v_tlf, {e_tf}, v_trf, 5367 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5368 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5369 */ 5370 { 5371 const PetscInt oc = 0; 5372 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5373 const PetscInt oft = ofb + PetscSqr(k-1); 5374 const PetscInt off = oft + PetscSqr(k-1); 5375 const PetscInt ofk = off + PetscSqr(k-1); 5376 const PetscInt ofr = ofk + PetscSqr(k-1); 5377 const PetscInt ofl = ofr + PetscSqr(k-1); 5378 const PetscInt oebl = ofl + PetscSqr(k-1); 5379 const PetscInt oebb = oebl + (k-1); 5380 const PetscInt oebr = oebb + (k-1); 5381 const PetscInt oebf = oebr + (k-1); 5382 const PetscInt oetf = oebf + (k-1); 5383 const PetscInt oetr = oetf + (k-1); 5384 const PetscInt oetb = oetr + (k-1); 5385 const PetscInt oetl = oetb + (k-1); 5386 const PetscInt oerf = oetl + (k-1); 5387 const PetscInt oelf = oerf + (k-1); 5388 const PetscInt oelb = oelf + (k-1); 5389 const PetscInt oerb = oelb + (k-1); 5390 const PetscInt ovblf = oerb + (k-1); 5391 const PetscInt ovblb = ovblf + 1; 5392 const PetscInt ovbrb = ovblb + 1; 5393 const PetscInt ovbrf = ovbrb + 1; 5394 const PetscInt ovtlf = ovbrf + 1; 5395 const PetscInt ovtrf = ovtlf + 1; 5396 const PetscInt ovtrb = ovtrf + 1; 5397 const PetscInt ovtlb = ovtrb + 1; 5398 PetscInt o, n; 5399 5400 /* Bottom Slice */ 5401 /* bottom */ 5402 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5403 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5404 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5405 /* middle */ 5406 for (i = 0; i < k-1; ++i) { 5407 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5408 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;} 5409 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5410 } 5411 /* top */ 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5413 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5414 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5415 5416 /* Middle Slice */ 5417 for (j = 0; j < k-1; ++j) { 5418 /* bottom */ 5419 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5420 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; 5421 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5422 /* middle */ 5423 for (i = 0; i < k-1; ++i) { 5424 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5425 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; 5426 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5427 } 5428 /* top */ 5429 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5430 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; 5431 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5432 } 5433 5434 /* Top Slice */ 5435 /* bottom */ 5436 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5437 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5438 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5439 /* middle */ 5440 for (i = 0; i < k-1; ++i) { 5441 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5442 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5443 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5444 } 5445 /* top */ 5446 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5447 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5448 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5449 5450 foffset = offset; 5451 } 5452 break; 5453 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5454 } 5455 } 5456 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5457 /* Check permutation */ 5458 { 5459 PetscInt *check; 5460 5461 PetscCall(PetscMalloc1(size, &check)); 5462 for (i = 0; i < size; ++i) { 5463 check[i] = -1; 5464 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5465 } 5466 for (i = 0; i < size; ++i) check[perm[i]] = i; 5467 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5468 PetscCall(PetscFree(check)); 5469 } 5470 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5471 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5472 PetscInt *loc_perm; 5473 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5474 for (PetscInt i=0; i<size; i++) { 5475 loc_perm[i] = perm[i]; 5476 loc_perm[size+i] = size + perm[i]; 5477 } 5478 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5479 } 5480 } 5481 PetscFunctionReturn(0); 5482 } 5483 5484 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5485 { 5486 PetscDS prob; 5487 PetscInt depth, Nf, h; 5488 DMLabel label; 5489 5490 PetscFunctionBeginHot; 5491 PetscCall(DMGetDS(dm, &prob)); 5492 Nf = prob->Nf; 5493 label = dm->depthLabel; 5494 *dspace = NULL; 5495 if (field < Nf) { 5496 PetscObject disc = prob->disc[field]; 5497 5498 if (disc->classid == PETSCFE_CLASSID) { 5499 PetscDualSpace dsp; 5500 5501 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5502 PetscCall(DMLabelGetNumValues(label,&depth)); 5503 PetscCall(DMLabelGetValue(label,point,&h)); 5504 h = depth - 1 - h; 5505 if (h) { 5506 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5507 } else { 5508 *dspace = dsp; 5509 } 5510 } 5511 } 5512 PetscFunctionReturn(0); 5513 } 5514 5515 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5516 { 5517 PetscScalar *array; 5518 const PetscScalar *vArray; 5519 const PetscInt *cone, *coneO; 5520 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5521 5522 PetscFunctionBeginHot; 5523 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5524 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5525 PetscCall(DMPlexGetCone(dm, point, &cone)); 5526 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5527 if (!values || !*values) { 5528 if ((point >= pStart) && (point < pEnd)) { 5529 PetscInt dof; 5530 5531 PetscCall(PetscSectionGetDof(section, point, &dof)); 5532 size += dof; 5533 } 5534 for (p = 0; p < numPoints; ++p) { 5535 const PetscInt cp = cone[p]; 5536 PetscInt dof; 5537 5538 if ((cp < pStart) || (cp >= pEnd)) continue; 5539 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5540 size += dof; 5541 } 5542 if (!values) { 5543 if (csize) *csize = size; 5544 PetscFunctionReturn(0); 5545 } 5546 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5547 } else { 5548 array = *values; 5549 } 5550 size = 0; 5551 PetscCall(VecGetArrayRead(v, &vArray)); 5552 if ((point >= pStart) && (point < pEnd)) { 5553 PetscInt dof, off, d; 5554 const PetscScalar *varr; 5555 5556 PetscCall(PetscSectionGetDof(section, point, &dof)); 5557 PetscCall(PetscSectionGetOffset(section, point, &off)); 5558 varr = &vArray[off]; 5559 for (d = 0; d < dof; ++d, ++offset) { 5560 array[offset] = varr[d]; 5561 } 5562 size += dof; 5563 } 5564 for (p = 0; p < numPoints; ++p) { 5565 const PetscInt cp = cone[p]; 5566 PetscInt o = coneO[p]; 5567 PetscInt dof, off, d; 5568 const PetscScalar *varr; 5569 5570 if ((cp < pStart) || (cp >= pEnd)) continue; 5571 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5572 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5573 varr = &vArray[off]; 5574 if (o >= 0) { 5575 for (d = 0; d < dof; ++d, ++offset) { 5576 array[offset] = varr[d]; 5577 } 5578 } else { 5579 for (d = dof-1; d >= 0; --d, ++offset) { 5580 array[offset] = varr[d]; 5581 } 5582 } 5583 size += dof; 5584 } 5585 PetscCall(VecRestoreArrayRead(v, &vArray)); 5586 if (!*values) { 5587 if (csize) *csize = size; 5588 *values = array; 5589 } else { 5590 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5591 *csize = size; 5592 } 5593 PetscFunctionReturn(0); 5594 } 5595 5596 /* Compress out points not in the section */ 5597 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5598 { 5599 const PetscInt np = *numPoints; 5600 PetscInt pStart, pEnd, p, q; 5601 5602 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5603 for (p = 0, q = 0; p < np; ++p) { 5604 const PetscInt r = points[p*2]; 5605 if ((r >= pStart) && (r < pEnd)) { 5606 points[q*2] = r; 5607 points[q*2+1] = points[p*2+1]; 5608 ++q; 5609 } 5610 } 5611 *numPoints = q; 5612 return 0; 5613 } 5614 5615 /* Compressed closure does not apply closure permutation */ 5616 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5617 { 5618 const PetscInt *cla = NULL; 5619 PetscInt np, *pts = NULL; 5620 5621 PetscFunctionBeginHot; 5622 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5623 if (*clPoints) { 5624 PetscInt dof, off; 5625 5626 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5627 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5628 PetscCall(ISGetIndices(*clPoints, &cla)); 5629 np = dof/2; 5630 pts = (PetscInt *) &cla[off]; 5631 } else { 5632 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5633 PetscCall(CompressPoints_Private(section, &np, pts)); 5634 } 5635 *numPoints = np; 5636 *points = pts; 5637 *clp = cla; 5638 PetscFunctionReturn(0); 5639 } 5640 5641 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5642 { 5643 PetscFunctionBeginHot; 5644 if (!*clPoints) { 5645 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5646 } else { 5647 PetscCall(ISRestoreIndices(*clPoints, clp)); 5648 } 5649 *numPoints = 0; 5650 *points = NULL; 5651 *clSec = NULL; 5652 *clPoints = NULL; 5653 *clp = NULL; 5654 PetscFunctionReturn(0); 5655 } 5656 5657 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5658 { 5659 PetscInt offset = 0, p; 5660 const PetscInt **perms = NULL; 5661 const PetscScalar **flips = NULL; 5662 5663 PetscFunctionBeginHot; 5664 *size = 0; 5665 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5666 for (p = 0; p < numPoints; p++) { 5667 const PetscInt point = points[2*p]; 5668 const PetscInt *perm = perms ? perms[p] : NULL; 5669 const PetscScalar *flip = flips ? flips[p] : NULL; 5670 PetscInt dof, off, d; 5671 const PetscScalar *varr; 5672 5673 PetscCall(PetscSectionGetDof(section, point, &dof)); 5674 PetscCall(PetscSectionGetOffset(section, point, &off)); 5675 varr = &vArray[off]; 5676 if (clperm) { 5677 if (perm) { 5678 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5679 } else { 5680 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5681 } 5682 if (flip) { 5683 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5684 } 5685 } else { 5686 if (perm) { 5687 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5688 } else { 5689 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5690 } 5691 if (flip) { 5692 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5693 } 5694 } 5695 offset += dof; 5696 } 5697 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5698 *size = offset; 5699 PetscFunctionReturn(0); 5700 } 5701 5702 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[]) 5703 { 5704 PetscInt offset = 0, f; 5705 5706 PetscFunctionBeginHot; 5707 *size = 0; 5708 for (f = 0; f < numFields; ++f) { 5709 PetscInt p; 5710 const PetscInt **perms = NULL; 5711 const PetscScalar **flips = NULL; 5712 5713 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5714 for (p = 0; p < numPoints; p++) { 5715 const PetscInt point = points[2*p]; 5716 PetscInt fdof, foff, b; 5717 const PetscScalar *varr; 5718 const PetscInt *perm = perms ? perms[p] : NULL; 5719 const PetscScalar *flip = flips ? flips[p] : NULL; 5720 5721 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5722 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5723 varr = &vArray[foff]; 5724 if (clperm) { 5725 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5726 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5727 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5728 } else { 5729 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5730 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5731 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5732 } 5733 offset += fdof; 5734 } 5735 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5736 } 5737 *size = offset; 5738 PetscFunctionReturn(0); 5739 } 5740 5741 /*@C 5742 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5743 5744 Not collective 5745 5746 Input Parameters: 5747 + dm - The DM 5748 . section - The section describing the layout in v, or NULL to use the default section 5749 . v - The local vector 5750 - point - The point in the DM 5751 5752 Input/Output Parameters: 5753 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5754 - values - An array to use for the values, or NULL to have it allocated automatically; 5755 if the user provided NULL, it is a borrowed array and should not be freed 5756 5757 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5758 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5759 $ assembly function, and a user may already have allocated storage for this operation. 5760 $ 5761 $ A typical use could be 5762 $ 5763 $ values = NULL; 5764 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5765 $ for (cl = 0; cl < clSize; ++cl) { 5766 $ <Compute on closure> 5767 $ } 5768 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5769 $ 5770 $ or 5771 $ 5772 $ PetscMalloc1(clMaxSize, &values); 5773 $ for (p = pStart; p < pEnd; ++p) { 5774 $ clSize = clMaxSize; 5775 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5776 $ for (cl = 0; cl < clSize; ++cl) { 5777 $ <Compute on closure> 5778 $ } 5779 $ } 5780 $ PetscFree(values); 5781 5782 Fortran Notes: 5783 Since it returns an array, this routine is only available in Fortran 90, and you must 5784 include petsc.h90 in your code. 5785 5786 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5787 5788 Level: intermediate 5789 5790 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5791 @*/ 5792 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5793 { 5794 PetscSection clSection; 5795 IS clPoints; 5796 PetscInt *points = NULL; 5797 const PetscInt *clp, *perm; 5798 PetscInt depth, numFields, numPoints, asize; 5799 5800 PetscFunctionBeginHot; 5801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5802 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5803 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5804 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5805 PetscCall(DMPlexGetDepth(dm, &depth)); 5806 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5807 if (depth == 1 && numFields < 2) { 5808 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5809 PetscFunctionReturn(0); 5810 } 5811 /* Get points */ 5812 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5813 /* Get sizes */ 5814 asize = 0; 5815 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5816 PetscInt dof; 5817 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5818 asize += dof; 5819 } 5820 if (values) { 5821 const PetscScalar *vArray; 5822 PetscInt size; 5823 5824 if (*values) { 5825 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); 5826 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5827 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5828 PetscCall(VecGetArrayRead(v, &vArray)); 5829 /* Get values */ 5830 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5831 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5832 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5833 /* Cleanup array */ 5834 PetscCall(VecRestoreArrayRead(v, &vArray)); 5835 } 5836 if (csize) *csize = asize; 5837 /* Cleanup points */ 5838 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5839 PetscFunctionReturn(0); 5840 } 5841 5842 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5843 { 5844 DMLabel depthLabel; 5845 PetscSection clSection; 5846 IS clPoints; 5847 PetscScalar *array; 5848 const PetscScalar *vArray; 5849 PetscInt *points = NULL; 5850 const PetscInt *clp, *perm = NULL; 5851 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5852 5853 PetscFunctionBeginHot; 5854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5855 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5856 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5857 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5858 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5859 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5860 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5861 if (mdepth == 1 && numFields < 2) { 5862 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5863 PetscFunctionReturn(0); 5864 } 5865 /* Get points */ 5866 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5867 for (clsize=0,p=0; p<Np; p++) { 5868 PetscInt dof; 5869 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5870 clsize += dof; 5871 } 5872 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5873 /* Filter points */ 5874 for (p = 0; p < numPoints*2; p += 2) { 5875 PetscInt dep; 5876 5877 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5878 if (dep != depth) continue; 5879 points[Np*2+0] = points[p]; 5880 points[Np*2+1] = points[p+1]; 5881 ++Np; 5882 } 5883 /* Get array */ 5884 if (!values || !*values) { 5885 PetscInt asize = 0, dof; 5886 5887 for (p = 0; p < Np*2; p += 2) { 5888 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5889 asize += dof; 5890 } 5891 if (!values) { 5892 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5893 if (csize) *csize = asize; 5894 PetscFunctionReturn(0); 5895 } 5896 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5897 } else { 5898 array = *values; 5899 } 5900 PetscCall(VecGetArrayRead(v, &vArray)); 5901 /* Get values */ 5902 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5903 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5904 /* Cleanup points */ 5905 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5906 /* Cleanup array */ 5907 PetscCall(VecRestoreArrayRead(v, &vArray)); 5908 if (!*values) { 5909 if (csize) *csize = size; 5910 *values = array; 5911 } else { 5912 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5913 *csize = size; 5914 } 5915 PetscFunctionReturn(0); 5916 } 5917 5918 /*@C 5919 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5920 5921 Not collective 5922 5923 Input Parameters: 5924 + dm - The DM 5925 . section - The section describing the layout in v, or NULL to use the default section 5926 . v - The local vector 5927 . point - The point in the DM 5928 . csize - The number of values in the closure, or NULL 5929 - values - The array of values, which is a borrowed array and should not be freed 5930 5931 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5932 5933 Fortran Notes: 5934 Since it returns an array, this routine is only available in Fortran 90, and you must 5935 include petsc.h90 in your code. 5936 5937 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5938 5939 Level: intermediate 5940 5941 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5942 @*/ 5943 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5944 { 5945 PetscInt size = 0; 5946 5947 PetscFunctionBegin; 5948 /* Should work without recalculating size */ 5949 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5950 *values = NULL; 5951 PetscFunctionReturn(0); 5952 } 5953 5954 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5955 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5956 5957 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[]) 5958 { 5959 PetscInt cdof; /* The number of constraints on this point */ 5960 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5961 PetscScalar *a; 5962 PetscInt off, cind = 0, k; 5963 5964 PetscFunctionBegin; 5965 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5966 PetscCall(PetscSectionGetOffset(section, point, &off)); 5967 a = &array[off]; 5968 if (!cdof || setBC) { 5969 if (clperm) { 5970 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5971 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5972 } else { 5973 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5974 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5975 } 5976 } else { 5977 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5978 if (clperm) { 5979 if (perm) {for (k = 0; k < dof; ++k) { 5980 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5981 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5982 } 5983 } else { 5984 for (k = 0; k < dof; ++k) { 5985 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5986 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5987 } 5988 } 5989 } else { 5990 if (perm) { 5991 for (k = 0; k < dof; ++k) { 5992 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5993 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5994 } 5995 } else { 5996 for (k = 0; k < dof; ++k) { 5997 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5998 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5999 } 6000 } 6001 } 6002 } 6003 PetscFunctionReturn(0); 6004 } 6005 6006 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[]) 6007 { 6008 PetscInt cdof; /* The number of constraints on this point */ 6009 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6010 PetscScalar *a; 6011 PetscInt off, cind = 0, k; 6012 6013 PetscFunctionBegin; 6014 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6015 PetscCall(PetscSectionGetOffset(section, point, &off)); 6016 a = &array[off]; 6017 if (cdof) { 6018 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6019 if (clperm) { 6020 if (perm) { 6021 for (k = 0; k < dof; ++k) { 6022 if ((cind < cdof) && (k == cdofs[cind])) { 6023 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6024 cind++; 6025 } 6026 } 6027 } else { 6028 for (k = 0; k < dof; ++k) { 6029 if ((cind < cdof) && (k == cdofs[cind])) { 6030 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6031 cind++; 6032 } 6033 } 6034 } 6035 } else { 6036 if (perm) { 6037 for (k = 0; k < dof; ++k) { 6038 if ((cind < cdof) && (k == cdofs[cind])) { 6039 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6040 cind++; 6041 } 6042 } 6043 } else { 6044 for (k = 0; k < dof; ++k) { 6045 if ((cind < cdof) && (k == cdofs[cind])) { 6046 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6047 cind++; 6048 } 6049 } 6050 } 6051 } 6052 } 6053 PetscFunctionReturn(0); 6054 } 6055 6056 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[]) 6057 { 6058 PetscScalar *a; 6059 PetscInt fdof, foff, fcdof, foffset = *offset; 6060 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6061 PetscInt cind = 0, b; 6062 6063 PetscFunctionBegin; 6064 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6065 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6066 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6067 a = &array[foff]; 6068 if (!fcdof || setBC) { 6069 if (clperm) { 6070 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6071 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6072 } else { 6073 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6074 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6075 } 6076 } else { 6077 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6078 if (clperm) { 6079 if (perm) { 6080 for (b = 0; b < fdof; b++) { 6081 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6082 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6083 } 6084 } else { 6085 for (b = 0; b < fdof; b++) { 6086 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6087 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6088 } 6089 } 6090 } else { 6091 if (perm) { 6092 for (b = 0; b < fdof; b++) { 6093 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6094 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6095 } 6096 } else { 6097 for (b = 0; b < fdof; b++) { 6098 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6099 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6100 } 6101 } 6102 } 6103 } 6104 *offset += fdof; 6105 PetscFunctionReturn(0); 6106 } 6107 6108 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[]) 6109 { 6110 PetscScalar *a; 6111 PetscInt fdof, foff, fcdof, foffset = *offset; 6112 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6113 PetscInt Nc, cind = 0, ncind = 0, b; 6114 PetscBool ncSet, fcSet; 6115 6116 PetscFunctionBegin; 6117 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6118 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6119 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6120 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6121 a = &array[foff]; 6122 if (fcdof) { 6123 /* We just override fcdof and fcdofs with Ncc and comps */ 6124 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6125 if (clperm) { 6126 if (perm) { 6127 if (comps) { 6128 for (b = 0; b < fdof; b++) { 6129 ncSet = fcSet = PETSC_FALSE; 6130 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6131 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6132 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6133 } 6134 } else { 6135 for (b = 0; b < fdof; b++) { 6136 if ((cind < fcdof) && (b == fcdofs[cind])) { 6137 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6138 ++cind; 6139 } 6140 } 6141 } 6142 } else { 6143 if (comps) { 6144 for (b = 0; b < fdof; b++) { 6145 ncSet = fcSet = PETSC_FALSE; 6146 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6147 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6148 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6149 } 6150 } else { 6151 for (b = 0; b < fdof; b++) { 6152 if ((cind < fcdof) && (b == fcdofs[cind])) { 6153 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6154 ++cind; 6155 } 6156 } 6157 } 6158 } 6159 } else { 6160 if (perm) { 6161 if (comps) { 6162 for (b = 0; b < fdof; b++) { 6163 ncSet = fcSet = PETSC_FALSE; 6164 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6165 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6166 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6167 } 6168 } else { 6169 for (b = 0; b < fdof; b++) { 6170 if ((cind < fcdof) && (b == fcdofs[cind])) { 6171 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6172 ++cind; 6173 } 6174 } 6175 } 6176 } else { 6177 if (comps) { 6178 for (b = 0; b < fdof; b++) { 6179 ncSet = fcSet = PETSC_FALSE; 6180 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6181 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6182 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6183 } 6184 } else { 6185 for (b = 0; b < fdof; b++) { 6186 if ((cind < fcdof) && (b == fcdofs[cind])) { 6187 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6188 ++cind; 6189 } 6190 } 6191 } 6192 } 6193 } 6194 } 6195 *offset += fdof; 6196 PetscFunctionReturn(0); 6197 } 6198 6199 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6200 { 6201 PetscScalar *array; 6202 const PetscInt *cone, *coneO; 6203 PetscInt pStart, pEnd, p, numPoints, off, dof; 6204 6205 PetscFunctionBeginHot; 6206 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6207 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6208 PetscCall(DMPlexGetCone(dm, point, &cone)); 6209 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6210 PetscCall(VecGetArray(v, &array)); 6211 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6212 const PetscInt cp = !p ? point : cone[p-1]; 6213 const PetscInt o = !p ? 0 : coneO[p-1]; 6214 6215 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6216 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6217 /* ADD_VALUES */ 6218 { 6219 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6220 PetscScalar *a; 6221 PetscInt cdof, coff, cind = 0, k; 6222 6223 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6224 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6225 a = &array[coff]; 6226 if (!cdof) { 6227 if (o >= 0) { 6228 for (k = 0; k < dof; ++k) { 6229 a[k] += values[off+k]; 6230 } 6231 } else { 6232 for (k = 0; k < dof; ++k) { 6233 a[k] += values[off+dof-k-1]; 6234 } 6235 } 6236 } else { 6237 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6238 if (o >= 0) { 6239 for (k = 0; k < dof; ++k) { 6240 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6241 a[k] += values[off+k]; 6242 } 6243 } else { 6244 for (k = 0; k < dof; ++k) { 6245 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6246 a[k] += values[off+dof-k-1]; 6247 } 6248 } 6249 } 6250 } 6251 } 6252 PetscCall(VecRestoreArray(v, &array)); 6253 PetscFunctionReturn(0); 6254 } 6255 6256 /*@C 6257 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6258 6259 Not collective 6260 6261 Input Parameters: 6262 + dm - The DM 6263 . section - The section describing the layout in v, or NULL to use the default section 6264 . v - The local vector 6265 . point - The point in the DM 6266 . values - The array of values 6267 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6268 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6269 6270 Fortran Notes: 6271 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6272 6273 Level: intermediate 6274 6275 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6276 @*/ 6277 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6278 { 6279 PetscSection clSection; 6280 IS clPoints; 6281 PetscScalar *array; 6282 PetscInt *points = NULL; 6283 const PetscInt *clp, *clperm = NULL; 6284 PetscInt depth, numFields, numPoints, p, clsize; 6285 6286 PetscFunctionBeginHot; 6287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6288 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6289 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6290 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6291 PetscCall(DMPlexGetDepth(dm, &depth)); 6292 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6293 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6294 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6295 PetscFunctionReturn(0); 6296 } 6297 /* Get points */ 6298 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6299 for (clsize=0,p=0; p<numPoints; p++) { 6300 PetscInt dof; 6301 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6302 clsize += dof; 6303 } 6304 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6305 /* Get array */ 6306 PetscCall(VecGetArray(v, &array)); 6307 /* Get values */ 6308 if (numFields > 0) { 6309 PetscInt offset = 0, f; 6310 for (f = 0; f < numFields; ++f) { 6311 const PetscInt **perms = NULL; 6312 const PetscScalar **flips = NULL; 6313 6314 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6315 switch (mode) { 6316 case INSERT_VALUES: 6317 for (p = 0; p < numPoints; p++) { 6318 const PetscInt point = points[2*p]; 6319 const PetscInt *perm = perms ? perms[p] : NULL; 6320 const PetscScalar *flip = flips ? flips[p] : NULL; 6321 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6322 } break; 6323 case INSERT_ALL_VALUES: 6324 for (p = 0; p < numPoints; p++) { 6325 const PetscInt point = points[2*p]; 6326 const PetscInt *perm = perms ? perms[p] : NULL; 6327 const PetscScalar *flip = flips ? flips[p] : NULL; 6328 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6329 } break; 6330 case INSERT_BC_VALUES: 6331 for (p = 0; p < numPoints; p++) { 6332 const PetscInt point = points[2*p]; 6333 const PetscInt *perm = perms ? perms[p] : NULL; 6334 const PetscScalar *flip = flips ? flips[p] : NULL; 6335 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6336 } break; 6337 case ADD_VALUES: 6338 for (p = 0; p < numPoints; p++) { 6339 const PetscInt point = points[2*p]; 6340 const PetscInt *perm = perms ? perms[p] : NULL; 6341 const PetscScalar *flip = flips ? flips[p] : NULL; 6342 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6343 } break; 6344 case ADD_ALL_VALUES: 6345 for (p = 0; p < numPoints; p++) { 6346 const PetscInt point = points[2*p]; 6347 const PetscInt *perm = perms ? perms[p] : NULL; 6348 const PetscScalar *flip = flips ? flips[p] : NULL; 6349 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6350 } break; 6351 case ADD_BC_VALUES: 6352 for (p = 0; p < numPoints; p++) { 6353 const PetscInt point = points[2*p]; 6354 const PetscInt *perm = perms ? perms[p] : NULL; 6355 const PetscScalar *flip = flips ? flips[p] : NULL; 6356 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6357 } break; 6358 default: 6359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6360 } 6361 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6362 } 6363 } else { 6364 PetscInt dof, off; 6365 const PetscInt **perms = NULL; 6366 const PetscScalar **flips = NULL; 6367 6368 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6369 switch (mode) { 6370 case INSERT_VALUES: 6371 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6372 const PetscInt point = points[2*p]; 6373 const PetscInt *perm = perms ? perms[p] : NULL; 6374 const PetscScalar *flip = flips ? flips[p] : NULL; 6375 PetscCall(PetscSectionGetDof(section, point, &dof)); 6376 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6377 } break; 6378 case INSERT_ALL_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_TRUE, perm, flip, clperm, values, off, array); 6385 } break; 6386 case INSERT_BC_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 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6393 } break; 6394 case ADD_VALUES: 6395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6396 const PetscInt point = points[2*p]; 6397 const PetscInt *perm = perms ? perms[p] : NULL; 6398 const PetscScalar *flip = flips ? flips[p] : NULL; 6399 PetscCall(PetscSectionGetDof(section, point, &dof)); 6400 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6401 } break; 6402 case ADD_ALL_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_TRUE, perm, flip, clperm, values, off, array); 6409 } break; 6410 case ADD_BC_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 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6417 } break; 6418 default: 6419 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6420 } 6421 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6422 } 6423 /* Cleanup points */ 6424 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6425 /* Cleanup array */ 6426 PetscCall(VecRestoreArray(v, &array)); 6427 PetscFunctionReturn(0); 6428 } 6429 6430 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6431 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6432 { 6433 PetscFunctionBegin; 6434 if (label) { 6435 PetscBool contains; 6436 PetscInt fdof; 6437 6438 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6439 if (!contains) { 6440 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6441 *offset += fdof; 6442 PetscFunctionReturn(1); 6443 } 6444 } 6445 PetscFunctionReturn(0); 6446 } 6447 6448 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6449 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) 6450 { 6451 PetscSection clSection; 6452 IS clPoints; 6453 PetscScalar *array; 6454 PetscInt *points = NULL; 6455 const PetscInt *clp; 6456 PetscInt numFields, numPoints, p; 6457 PetscInt offset = 0, f; 6458 6459 PetscFunctionBeginHot; 6460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6461 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6462 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6463 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6464 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6465 /* Get points */ 6466 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6467 /* Get array */ 6468 PetscCall(VecGetArray(v, &array)); 6469 /* Get values */ 6470 for (f = 0; f < numFields; ++f) { 6471 const PetscInt **perms = NULL; 6472 const PetscScalar **flips = NULL; 6473 6474 if (!fieldActive[f]) { 6475 for (p = 0; p < numPoints*2; p += 2) { 6476 PetscInt fdof; 6477 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6478 offset += fdof; 6479 } 6480 continue; 6481 } 6482 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6483 switch (mode) { 6484 case INSERT_VALUES: 6485 for (p = 0; p < numPoints; p++) { 6486 const PetscInt point = points[2*p]; 6487 const PetscInt *perm = perms ? perms[p] : NULL; 6488 const PetscScalar *flip = flips ? flips[p] : NULL; 6489 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6490 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6491 } break; 6492 case INSERT_ALL_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_TRUE, NULL, values, &offset, array)); 6499 } break; 6500 case INSERT_BC_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(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6507 } break; 6508 case ADD_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2*p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6514 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6515 } break; 6516 case ADD_ALL_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_TRUE, NULL, values, &offset, array)); 6523 } break; 6524 default: 6525 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6526 } 6527 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6528 } 6529 /* Cleanup points */ 6530 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6531 /* Cleanup array */ 6532 PetscCall(VecRestoreArray(v, &array)); 6533 PetscFunctionReturn(0); 6534 } 6535 6536 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6537 { 6538 PetscMPIInt rank; 6539 PetscInt i, j; 6540 6541 PetscFunctionBegin; 6542 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6543 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6544 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6545 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6546 numCIndices = numCIndices ? numCIndices : numRIndices; 6547 if (!values) PetscFunctionReturn(0); 6548 for (i = 0; i < numRIndices; i++) { 6549 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6550 for (j = 0; j < numCIndices; j++) { 6551 #if defined(PETSC_USE_COMPLEX) 6552 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6553 #else 6554 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6555 #endif 6556 } 6557 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6558 } 6559 PetscFunctionReturn(0); 6560 } 6561 6562 /* 6563 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6564 6565 Input Parameters: 6566 + section - The section for this data layout 6567 . islocal - Is the section (and thus indices being requested) local or global? 6568 . point - The point contributing dofs with these indices 6569 . off - The global offset of this point 6570 . loff - The local offset of each field 6571 . setBC - The flag determining whether to include indices of boundary values 6572 . perm - A permutation of the dofs on this point, or NULL 6573 - indperm - A permutation of the entire indices array, or NULL 6574 6575 Output Parameter: 6576 . indices - Indices for dofs on this point 6577 6578 Level: developer 6579 6580 Note: The indices could be local or global, depending on the value of 'off'. 6581 */ 6582 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6583 { 6584 PetscInt dof; /* The number of unknowns on this point */ 6585 PetscInt cdof; /* The number of constraints on this point */ 6586 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6587 PetscInt cind = 0, k; 6588 6589 PetscFunctionBegin; 6590 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6591 PetscCall(PetscSectionGetDof(section, point, &dof)); 6592 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6593 if (!cdof || setBC) { 6594 for (k = 0; k < dof; ++k) { 6595 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6596 const PetscInt ind = indperm ? indperm[preind] : preind; 6597 6598 indices[ind] = off + k; 6599 } 6600 } else { 6601 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 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 if ((cind < cdof) && (k == cdofs[cind])) { 6607 /* Insert check for returning constrained indices */ 6608 indices[ind] = -(off+k+1); 6609 ++cind; 6610 } else { 6611 indices[ind] = off + k - (islocal ? 0 : cind); 6612 } 6613 } 6614 } 6615 *loff += dof; 6616 PetscFunctionReturn(0); 6617 } 6618 6619 /* 6620 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6621 6622 Input Parameters: 6623 + section - a section (global or local) 6624 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6625 . point - point within section 6626 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6627 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6628 . setBC - identify constrained (boundary condition) points via involution. 6629 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6630 . permsoff - offset 6631 - indperm - index permutation 6632 6633 Output Parameter: 6634 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6635 . indices - array to hold indices (as defined by section) of each dof associated with point 6636 6637 Notes: 6638 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6639 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6640 in the local vector. 6641 6642 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6643 significant). It is invalid to call with a global section and setBC=true. 6644 6645 Developer Note: 6646 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6647 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6648 offset could be obtained from the section instead of passing it explicitly as we do now. 6649 6650 Example: 6651 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6652 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6653 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6654 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. 6655 6656 Level: developer 6657 */ 6658 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[]) 6659 { 6660 PetscInt numFields, foff, f; 6661 6662 PetscFunctionBegin; 6663 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6664 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6665 for (f = 0, foff = 0; f < numFields; ++f) { 6666 PetscInt fdof, cfdof; 6667 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6668 PetscInt cind = 0, b; 6669 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6670 6671 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6672 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6673 if (!cfdof || setBC) { 6674 for (b = 0; b < fdof; ++b) { 6675 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6676 const PetscInt ind = indperm ? indperm[preind] : preind; 6677 6678 indices[ind] = off+foff+b; 6679 } 6680 } else { 6681 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 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 if ((cind < cfdof) && (b == fcdofs[cind])) { 6687 indices[ind] = -(off+foff+b+1); 6688 ++cind; 6689 } else { 6690 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6691 } 6692 } 6693 } 6694 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6695 foffs[f] += fdof; 6696 } 6697 PetscFunctionReturn(0); 6698 } 6699 6700 /* 6701 This version believes the globalSection offsets for each field, rather than just the point offset 6702 6703 . foffs - The offset into 'indices' for each field, since it is segregated by field 6704 6705 Notes: 6706 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6707 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6708 */ 6709 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6710 { 6711 PetscInt numFields, foff, f; 6712 6713 PetscFunctionBegin; 6714 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6715 for (f = 0; f < numFields; ++f) { 6716 PetscInt fdof, cfdof; 6717 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6718 PetscInt cind = 0, b; 6719 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6720 6721 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6722 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6723 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6724 if (!cfdof) { 6725 for (b = 0; b < fdof; ++b) { 6726 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6727 const PetscInt ind = indperm ? indperm[preind] : preind; 6728 6729 indices[ind] = foff+b; 6730 } 6731 } else { 6732 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 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 if ((cind < cfdof) && (b == fcdofs[cind])) { 6738 indices[ind] = -(foff+b+1); 6739 ++cind; 6740 } else { 6741 indices[ind] = foff+b-cind; 6742 } 6743 } 6744 } 6745 foffs[f] += fdof; 6746 } 6747 PetscFunctionReturn(0); 6748 } 6749 6750 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) 6751 { 6752 Mat cMat; 6753 PetscSection aSec, cSec; 6754 IS aIS; 6755 PetscInt aStart = -1, aEnd = -1; 6756 const PetscInt *anchors; 6757 PetscInt numFields, f, p, q, newP = 0; 6758 PetscInt newNumPoints = 0, newNumIndices = 0; 6759 PetscInt *newPoints, *indices, *newIndices; 6760 PetscInt maxAnchor, maxDof; 6761 PetscInt newOffsets[32]; 6762 PetscInt *pointMatOffsets[32]; 6763 PetscInt *newPointOffsets[32]; 6764 PetscScalar *pointMat[32]; 6765 PetscScalar *newValues=NULL,*tmpValues; 6766 PetscBool anyConstrained = PETSC_FALSE; 6767 6768 PetscFunctionBegin; 6769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6770 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6771 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6772 6773 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6774 /* if there are point-to-point constraints */ 6775 if (aSec) { 6776 PetscCall(PetscArrayzero(newOffsets, 32)); 6777 PetscCall(ISGetIndices(aIS,&anchors)); 6778 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6779 /* figure out how many points are going to be in the new element matrix 6780 * (we allow double counting, because it's all just going to be summed 6781 * into the global matrix anyway) */ 6782 for (p = 0; p < 2*numPoints; p+=2) { 6783 PetscInt b = points[p]; 6784 PetscInt bDof = 0, bSecDof; 6785 6786 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6787 if (!bSecDof) { 6788 continue; 6789 } 6790 if (b >= aStart && b < aEnd) { 6791 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6792 } 6793 if (bDof) { 6794 /* this point is constrained */ 6795 /* it is going to be replaced by its anchors */ 6796 PetscInt bOff, q; 6797 6798 anyConstrained = PETSC_TRUE; 6799 newNumPoints += bDof; 6800 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6801 for (q = 0; q < bDof; q++) { 6802 PetscInt a = anchors[bOff + q]; 6803 PetscInt aDof; 6804 6805 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6806 newNumIndices += aDof; 6807 for (f = 0; f < numFields; ++f) { 6808 PetscInt fDof; 6809 6810 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6811 newOffsets[f+1] += fDof; 6812 } 6813 } 6814 } 6815 else { 6816 /* this point is not constrained */ 6817 newNumPoints++; 6818 newNumIndices += bSecDof; 6819 for (f = 0; f < numFields; ++f) { 6820 PetscInt fDof; 6821 6822 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6823 newOffsets[f+1] += fDof; 6824 } 6825 } 6826 } 6827 } 6828 if (!anyConstrained) { 6829 if (outNumPoints) *outNumPoints = 0; 6830 if (outNumIndices) *outNumIndices = 0; 6831 if (outPoints) *outPoints = NULL; 6832 if (outValues) *outValues = NULL; 6833 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6834 PetscFunctionReturn(0); 6835 } 6836 6837 if (outNumPoints) *outNumPoints = newNumPoints; 6838 if (outNumIndices) *outNumIndices = newNumIndices; 6839 6840 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6841 6842 if (!outPoints && !outValues) { 6843 if (offsets) { 6844 for (f = 0; f <= numFields; f++) { 6845 offsets[f] = newOffsets[f]; 6846 } 6847 } 6848 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6849 PetscFunctionReturn(0); 6850 } 6851 6852 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6853 6854 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6855 6856 /* workspaces */ 6857 if (numFields) { 6858 for (f = 0; f < numFields; f++) { 6859 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6860 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6861 } 6862 } 6863 else { 6864 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6865 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6866 } 6867 6868 /* get workspaces for the point-to-point matrices */ 6869 if (numFields) { 6870 PetscInt totalOffset, totalMatOffset; 6871 6872 for (p = 0; p < numPoints; p++) { 6873 PetscInt b = points[2*p]; 6874 PetscInt bDof = 0, bSecDof; 6875 6876 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6877 if (!bSecDof) { 6878 for (f = 0; f < numFields; f++) { 6879 newPointOffsets[f][p + 1] = 0; 6880 pointMatOffsets[f][p + 1] = 0; 6881 } 6882 continue; 6883 } 6884 if (b >= aStart && b < aEnd) { 6885 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6886 } 6887 if (bDof) { 6888 for (f = 0; f < numFields; f++) { 6889 PetscInt fDof, q, bOff, allFDof = 0; 6890 6891 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6892 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6893 for (q = 0; q < bDof; q++) { 6894 PetscInt a = anchors[bOff + q]; 6895 PetscInt aFDof; 6896 6897 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6898 allFDof += aFDof; 6899 } 6900 newPointOffsets[f][p+1] = allFDof; 6901 pointMatOffsets[f][p+1] = fDof * allFDof; 6902 } 6903 } 6904 else { 6905 for (f = 0; f < numFields; f++) { 6906 PetscInt fDof; 6907 6908 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6909 newPointOffsets[f][p+1] = fDof; 6910 pointMatOffsets[f][p+1] = 0; 6911 } 6912 } 6913 } 6914 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6915 newPointOffsets[f][0] = totalOffset; 6916 pointMatOffsets[f][0] = totalMatOffset; 6917 for (p = 0; p < numPoints; p++) { 6918 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6919 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6920 } 6921 totalOffset = newPointOffsets[f][numPoints]; 6922 totalMatOffset = pointMatOffsets[f][numPoints]; 6923 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6924 } 6925 } 6926 else { 6927 for (p = 0; p < numPoints; p++) { 6928 PetscInt b = points[2*p]; 6929 PetscInt bDof = 0, bSecDof; 6930 6931 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6932 if (!bSecDof) { 6933 newPointOffsets[0][p + 1] = 0; 6934 pointMatOffsets[0][p + 1] = 0; 6935 continue; 6936 } 6937 if (b >= aStart && b < aEnd) { 6938 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6939 } 6940 if (bDof) { 6941 PetscInt bOff, q, allDof = 0; 6942 6943 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6944 for (q = 0; q < bDof; q++) { 6945 PetscInt a = anchors[bOff + q], aDof; 6946 6947 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6948 allDof += aDof; 6949 } 6950 newPointOffsets[0][p+1] = allDof; 6951 pointMatOffsets[0][p+1] = bSecDof * allDof; 6952 } 6953 else { 6954 newPointOffsets[0][p+1] = bSecDof; 6955 pointMatOffsets[0][p+1] = 0; 6956 } 6957 } 6958 newPointOffsets[0][0] = 0; 6959 pointMatOffsets[0][0] = 0; 6960 for (p = 0; p < numPoints; p++) { 6961 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6962 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6963 } 6964 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6965 } 6966 6967 /* output arrays */ 6968 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6969 6970 /* get the point-to-point matrices; construct newPoints */ 6971 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6972 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6973 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6974 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6975 if (numFields) { 6976 for (p = 0, newP = 0; p < numPoints; p++) { 6977 PetscInt b = points[2*p]; 6978 PetscInt o = points[2*p+1]; 6979 PetscInt bDof = 0, bSecDof; 6980 6981 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6982 if (!bSecDof) { 6983 continue; 6984 } 6985 if (b >= aStart && b < aEnd) { 6986 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6987 } 6988 if (bDof) { 6989 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6990 6991 fStart[0] = 0; 6992 fEnd[0] = 0; 6993 for (f = 0; f < numFields; f++) { 6994 PetscInt fDof; 6995 6996 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6997 fStart[f+1] = fStart[f] + fDof; 6998 fEnd[f+1] = fStart[f+1]; 6999 } 7000 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7001 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7002 7003 fAnchorStart[0] = 0; 7004 fAnchorEnd[0] = 0; 7005 for (f = 0; f < numFields; f++) { 7006 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7007 7008 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7009 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7010 } 7011 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7012 for (q = 0; q < bDof; q++) { 7013 PetscInt a = anchors[bOff + q], aOff; 7014 7015 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7016 newPoints[2*(newP + q)] = a; 7017 newPoints[2*(newP + q) + 1] = 0; 7018 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7019 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7020 } 7021 newP += bDof; 7022 7023 if (outValues) { 7024 /* get the point-to-point submatrix */ 7025 for (f = 0; f < numFields; f++) { 7026 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7027 } 7028 } 7029 } 7030 else { 7031 newPoints[2 * newP] = b; 7032 newPoints[2 * newP + 1] = o; 7033 newP++; 7034 } 7035 } 7036 } else { 7037 for (p = 0; p < numPoints; p++) { 7038 PetscInt b = points[2*p]; 7039 PetscInt o = points[2*p+1]; 7040 PetscInt bDof = 0, bSecDof; 7041 7042 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7043 if (!bSecDof) { 7044 continue; 7045 } 7046 if (b >= aStart && b < aEnd) { 7047 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7048 } 7049 if (bDof) { 7050 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7051 7052 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7053 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7054 7055 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7056 for (q = 0; q < bDof; q++) { 7057 PetscInt a = anchors[bOff + q], aOff; 7058 7059 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7060 7061 newPoints[2*(newP + q)] = a; 7062 newPoints[2*(newP + q) + 1] = 0; 7063 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7064 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7065 } 7066 newP += bDof; 7067 7068 /* get the point-to-point submatrix */ 7069 if (outValues) { 7070 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7071 } 7072 } 7073 else { 7074 newPoints[2 * newP] = b; 7075 newPoints[2 * newP + 1] = o; 7076 newP++; 7077 } 7078 } 7079 } 7080 7081 if (outValues) { 7082 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7083 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7084 /* multiply constraints on the right */ 7085 if (numFields) { 7086 for (f = 0; f < numFields; f++) { 7087 PetscInt oldOff = offsets[f]; 7088 7089 for (p = 0; p < numPoints; p++) { 7090 PetscInt cStart = newPointOffsets[f][p]; 7091 PetscInt b = points[2 * p]; 7092 PetscInt c, r, k; 7093 PetscInt dof; 7094 7095 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7096 if (!dof) { 7097 continue; 7098 } 7099 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7100 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7101 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7102 7103 for (r = 0; r < numIndices; r++) { 7104 for (c = 0; c < nCols; c++) { 7105 for (k = 0; k < dof; k++) { 7106 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7107 } 7108 } 7109 } 7110 } 7111 else { 7112 /* copy this column as is */ 7113 for (r = 0; r < numIndices; r++) { 7114 for (c = 0; c < dof; c++) { 7115 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7116 } 7117 } 7118 } 7119 oldOff += dof; 7120 } 7121 } 7122 } 7123 else { 7124 PetscInt oldOff = 0; 7125 for (p = 0; p < numPoints; p++) { 7126 PetscInt cStart = newPointOffsets[0][p]; 7127 PetscInt b = points[2 * p]; 7128 PetscInt c, r, k; 7129 PetscInt dof; 7130 7131 PetscCall(PetscSectionGetDof(section,b,&dof)); 7132 if (!dof) { 7133 continue; 7134 } 7135 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7136 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7137 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7138 7139 for (r = 0; r < numIndices; r++) { 7140 for (c = 0; c < nCols; c++) { 7141 for (k = 0; k < dof; k++) { 7142 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7143 } 7144 } 7145 } 7146 } 7147 else { 7148 /* copy this column as is */ 7149 for (r = 0; r < numIndices; r++) { 7150 for (c = 0; c < dof; c++) { 7151 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7152 } 7153 } 7154 } 7155 oldOff += dof; 7156 } 7157 } 7158 7159 if (multiplyLeft) { 7160 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7161 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7162 /* multiply constraints transpose on the left */ 7163 if (numFields) { 7164 for (f = 0; f < numFields; f++) { 7165 PetscInt oldOff = offsets[f]; 7166 7167 for (p = 0; p < numPoints; p++) { 7168 PetscInt rStart = newPointOffsets[f][p]; 7169 PetscInt b = points[2 * p]; 7170 PetscInt c, r, k; 7171 PetscInt dof; 7172 7173 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7174 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7175 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7176 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7177 7178 for (r = 0; r < nRows; r++) { 7179 for (c = 0; c < newNumIndices; c++) { 7180 for (k = 0; k < dof; k++) { 7181 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7182 } 7183 } 7184 } 7185 } 7186 else { 7187 /* copy this row as is */ 7188 for (r = 0; r < dof; r++) { 7189 for (c = 0; c < newNumIndices; c++) { 7190 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7191 } 7192 } 7193 } 7194 oldOff += dof; 7195 } 7196 } 7197 } 7198 else { 7199 PetscInt oldOff = 0; 7200 7201 for (p = 0; p < numPoints; p++) { 7202 PetscInt rStart = newPointOffsets[0][p]; 7203 PetscInt b = points[2 * p]; 7204 PetscInt c, r, k; 7205 PetscInt dof; 7206 7207 PetscCall(PetscSectionGetDof(section,b,&dof)); 7208 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7209 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7210 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7211 7212 for (r = 0; r < nRows; r++) { 7213 for (c = 0; c < newNumIndices; c++) { 7214 for (k = 0; k < dof; k++) { 7215 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7216 } 7217 } 7218 } 7219 } 7220 else { 7221 /* copy this row as is */ 7222 for (r = 0; r < dof; r++) { 7223 for (c = 0; c < newNumIndices; c++) { 7224 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7225 } 7226 } 7227 } 7228 oldOff += dof; 7229 } 7230 } 7231 7232 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7233 } 7234 else { 7235 newValues = tmpValues; 7236 } 7237 } 7238 7239 /* clean up */ 7240 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7241 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7242 7243 if (numFields) { 7244 for (f = 0; f < numFields; f++) { 7245 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7246 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7247 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7248 } 7249 } 7250 else { 7251 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7252 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7253 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7254 } 7255 PetscCall(ISRestoreIndices(aIS,&anchors)); 7256 7257 /* output */ 7258 if (outPoints) { 7259 *outPoints = newPoints; 7260 } 7261 else { 7262 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7263 } 7264 if (outValues) { 7265 *outValues = newValues; 7266 } 7267 for (f = 0; f <= numFields; f++) { 7268 offsets[f] = newOffsets[f]; 7269 } 7270 PetscFunctionReturn(0); 7271 } 7272 7273 /*@C 7274 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7275 7276 Not collective 7277 7278 Input Parameters: 7279 + dm - The DM 7280 . section - The PetscSection describing the points (a local section) 7281 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7282 . point - The point defining the closure 7283 - useClPerm - Use the closure point permutation if available 7284 7285 Output Parameters: 7286 + numIndices - The number of dof indices in the closure of point with the input sections 7287 . indices - The dof indices 7288 . outOffsets - Array to write the field offsets into, or NULL 7289 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7290 7291 Notes: 7292 Must call DMPlexRestoreClosureIndices() to free allocated memory 7293 7294 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7295 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7296 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7297 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7298 indices (with the above semantics) are implied. 7299 7300 Level: advanced 7301 7302 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7303 @*/ 7304 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7305 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7306 { 7307 /* Closure ordering */ 7308 PetscSection clSection; 7309 IS clPoints; 7310 const PetscInt *clp; 7311 PetscInt *points; 7312 const PetscInt *clperm = NULL; 7313 /* Dof permutation and sign flips */ 7314 const PetscInt **perms[32] = {NULL}; 7315 const PetscScalar **flips[32] = {NULL}; 7316 PetscScalar *valCopy = NULL; 7317 /* Hanging node constraints */ 7318 PetscInt *pointsC = NULL; 7319 PetscScalar *valuesC = NULL; 7320 PetscInt NclC, NiC; 7321 7322 PetscInt *idx; 7323 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7324 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7325 7326 PetscFunctionBeginHot; 7327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7328 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7329 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7330 if (numIndices) PetscValidIntPointer(numIndices, 6); 7331 if (indices) PetscValidPointer(indices, 7); 7332 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7333 if (values) PetscValidPointer(values, 9); 7334 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7335 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7336 PetscCall(PetscArrayzero(offsets, 32)); 7337 /* 1) Get points in closure */ 7338 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7339 if (useClPerm) { 7340 PetscInt depth, clsize; 7341 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7342 for (clsize=0,p=0; p<Ncl; p++) { 7343 PetscInt dof; 7344 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7345 clsize += dof; 7346 } 7347 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7348 } 7349 /* 2) Get number of indices on these points and field offsets from section */ 7350 for (p = 0; p < Ncl*2; p += 2) { 7351 PetscInt dof, fdof; 7352 7353 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7354 for (f = 0; f < Nf; ++f) { 7355 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7356 offsets[f+1] += fdof; 7357 } 7358 Ni += dof; 7359 } 7360 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7361 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7362 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7363 for (f = 0; f < PetscMax(1, Nf); ++f) { 7364 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7365 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7366 /* may need to apply sign changes to the element matrix */ 7367 if (values && flips[f]) { 7368 PetscInt foffset = offsets[f]; 7369 7370 for (p = 0; p < Ncl; ++p) { 7371 PetscInt pnt = points[2*p], fdof; 7372 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7373 7374 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7375 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7376 if (flip) { 7377 PetscInt i, j, k; 7378 7379 if (!valCopy) { 7380 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7381 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7382 *values = valCopy; 7383 } 7384 for (i = 0; i < fdof; ++i) { 7385 PetscScalar fval = flip[i]; 7386 7387 for (k = 0; k < Ni; ++k) { 7388 valCopy[Ni * (foffset + i) + k] *= fval; 7389 valCopy[Ni * k + (foffset + i)] *= fval; 7390 } 7391 } 7392 } 7393 foffset += fdof; 7394 } 7395 } 7396 } 7397 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7398 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7399 if (NclC) { 7400 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7401 for (f = 0; f < PetscMax(1, Nf); ++f) { 7402 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7403 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7404 } 7405 for (f = 0; f < PetscMax(1, Nf); ++f) { 7406 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7407 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7408 } 7409 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7410 Ncl = NclC; 7411 Ni = NiC; 7412 points = pointsC; 7413 if (values) *values = valuesC; 7414 } 7415 /* 5) Calculate indices */ 7416 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7417 if (Nf) { 7418 PetscInt idxOff; 7419 PetscBool useFieldOffsets; 7420 7421 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7422 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7423 if (useFieldOffsets) { 7424 for (p = 0; p < Ncl; ++p) { 7425 const PetscInt pnt = points[p*2]; 7426 7427 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7428 } 7429 } else { 7430 for (p = 0; p < Ncl; ++p) { 7431 const PetscInt pnt = points[p*2]; 7432 7433 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7434 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7435 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7436 * global section. */ 7437 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7438 } 7439 } 7440 } else { 7441 PetscInt off = 0, idxOff; 7442 7443 for (p = 0; p < Ncl; ++p) { 7444 const PetscInt pnt = points[p*2]; 7445 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7446 7447 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7448 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7449 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7450 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7451 } 7452 } 7453 /* 6) Cleanup */ 7454 for (f = 0; f < PetscMax(1, Nf); ++f) { 7455 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7456 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7457 } 7458 if (NclC) { 7459 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7460 } else { 7461 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7462 } 7463 7464 if (numIndices) *numIndices = Ni; 7465 if (indices) *indices = idx; 7466 PetscFunctionReturn(0); 7467 } 7468 7469 /*@C 7470 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7471 7472 Not collective 7473 7474 Input Parameters: 7475 + dm - The DM 7476 . section - The PetscSection describing the points (a local section) 7477 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7478 . point - The point defining the closure 7479 - useClPerm - Use the closure point permutation if available 7480 7481 Output Parameters: 7482 + numIndices - The number of dof indices in the closure of point with the input sections 7483 . indices - The dof indices 7484 . outOffsets - Array to write the field offsets into, or NULL 7485 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7486 7487 Notes: 7488 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7489 7490 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7491 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7492 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7493 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7494 indices (with the above semantics) are implied. 7495 7496 Level: advanced 7497 7498 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7499 @*/ 7500 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7501 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7502 { 7503 PetscFunctionBegin; 7504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7505 PetscValidPointer(indices, 7); 7506 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7507 PetscFunctionReturn(0); 7508 } 7509 7510 /*@C 7511 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7512 7513 Not collective 7514 7515 Input Parameters: 7516 + dm - The DM 7517 . section - The section describing the layout in v, or NULL to use the default section 7518 . globalSection - The section describing the layout in v, or NULL to use the default global section 7519 . A - The matrix 7520 . point - The point in the DM 7521 . values - The array of values 7522 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7523 7524 Fortran Notes: 7525 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7526 7527 Level: intermediate 7528 7529 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7530 @*/ 7531 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7532 { 7533 DM_Plex *mesh = (DM_Plex*) dm->data; 7534 PetscInt *indices; 7535 PetscInt numIndices; 7536 const PetscScalar *valuesOrig = values; 7537 PetscErrorCode ierr; 7538 7539 PetscFunctionBegin; 7540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7541 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7542 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7543 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7544 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7545 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7546 7547 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7548 7549 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7550 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7551 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7552 if (ierr) { 7553 PetscMPIInt rank; 7554 7555 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7556 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7557 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7558 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7559 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7560 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7561 } 7562 if (mesh->printFEM > 1) { 7563 PetscInt i; 7564 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7565 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7566 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7567 } 7568 7569 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7570 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7571 PetscFunctionReturn(0); 7572 } 7573 7574 /*@C 7575 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7576 7577 Not collective 7578 7579 Input Parameters: 7580 + dmRow - The DM for the row fields 7581 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7582 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7583 . dmCol - The DM for the column fields 7584 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7585 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7586 . A - The matrix 7587 . point - The point in the DMs 7588 . values - The array of values 7589 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7590 7591 Level: intermediate 7592 7593 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7594 @*/ 7595 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7596 { 7597 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7598 PetscInt *indicesRow, *indicesCol; 7599 PetscInt numIndicesRow, numIndicesCol; 7600 const PetscScalar *valuesOrig = values; 7601 PetscErrorCode ierr; 7602 7603 PetscFunctionBegin; 7604 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7605 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7606 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7607 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7608 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7609 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7610 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7611 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7612 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7613 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7614 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7615 7616 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7617 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7618 7619 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7620 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7621 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7622 if (ierr) { 7623 PetscMPIInt rank; 7624 7625 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7626 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7627 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7628 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7629 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7630 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7631 } 7632 7633 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7634 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7635 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7636 PetscFunctionReturn(0); 7637 } 7638 7639 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7640 { 7641 DM_Plex *mesh = (DM_Plex*) dmf->data; 7642 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7643 PetscInt *cpoints = NULL; 7644 PetscInt *findices, *cindices; 7645 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7646 PetscInt foffsets[32], coffsets[32]; 7647 DMPolytopeType ct; 7648 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7649 PetscErrorCode ierr; 7650 7651 PetscFunctionBegin; 7652 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7653 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7654 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7655 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7656 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7657 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7658 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7659 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7660 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7661 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7662 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7663 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7664 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7665 PetscCall(PetscArrayzero(foffsets, 32)); 7666 PetscCall(PetscArrayzero(coffsets, 32)); 7667 /* Column indices */ 7668 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7669 maxFPoints = numCPoints; 7670 /* Compress out points not in the section */ 7671 /* TODO: Squeeze out points with 0 dof as well */ 7672 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7673 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7674 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7675 cpoints[q*2] = cpoints[p]; 7676 cpoints[q*2+1] = cpoints[p+1]; 7677 ++q; 7678 } 7679 } 7680 numCPoints = q; 7681 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7682 PetscInt fdof; 7683 7684 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7685 if (!dof) continue; 7686 for (f = 0; f < numFields; ++f) { 7687 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7688 coffsets[f+1] += fdof; 7689 } 7690 numCIndices += dof; 7691 } 7692 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7693 /* Row indices */ 7694 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7695 { 7696 DMPlexTransform tr; 7697 DMPolytopeType *rct; 7698 PetscInt *rsize, *rcone, *rornt, Nt; 7699 7700 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7701 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7702 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7703 numSubcells = rsize[Nt-1]; 7704 PetscCall(DMPlexTransformDestroy(&tr)); 7705 } 7706 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7707 for (r = 0, q = 0; r < numSubcells; ++r) { 7708 /* TODO Map from coarse to fine cells */ 7709 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7710 /* Compress out points not in the section */ 7711 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7712 for (p = 0; p < numFPoints*2; p += 2) { 7713 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7714 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7715 if (!dof) continue; 7716 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7717 if (s < q) continue; 7718 ftotpoints[q*2] = fpoints[p]; 7719 ftotpoints[q*2+1] = fpoints[p+1]; 7720 ++q; 7721 } 7722 } 7723 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7724 } 7725 numFPoints = q; 7726 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7727 PetscInt fdof; 7728 7729 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7730 if (!dof) continue; 7731 for (f = 0; f < numFields; ++f) { 7732 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7733 foffsets[f+1] += fdof; 7734 } 7735 numFIndices += dof; 7736 } 7737 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7738 7739 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7740 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7741 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7742 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7743 if (numFields) { 7744 const PetscInt **permsF[32] = {NULL}; 7745 const PetscInt **permsC[32] = {NULL}; 7746 7747 for (f = 0; f < numFields; f++) { 7748 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7749 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7750 } 7751 for (p = 0; p < numFPoints; p++) { 7752 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7753 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7754 } 7755 for (p = 0; p < numCPoints; p++) { 7756 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7757 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7758 } 7759 for (f = 0; f < numFields; f++) { 7760 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7761 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7762 } 7763 } else { 7764 const PetscInt **permsF = NULL; 7765 const PetscInt **permsC = NULL; 7766 7767 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7768 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7769 for (p = 0, off = 0; p < numFPoints; p++) { 7770 const PetscInt *perm = permsF ? permsF[p] : NULL; 7771 7772 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7773 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7774 } 7775 for (p = 0, off = 0; p < numCPoints; p++) { 7776 const PetscInt *perm = permsC ? permsC[p] : NULL; 7777 7778 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7779 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7780 } 7781 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7782 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7783 } 7784 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7785 /* TODO: flips */ 7786 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7787 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7788 if (ierr) { 7789 PetscMPIInt rank; 7790 7791 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7792 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7793 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7794 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7795 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7796 } 7797 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7798 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7799 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7800 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7801 PetscFunctionReturn(0); 7802 } 7803 7804 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7805 { 7806 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7807 PetscInt *cpoints = NULL; 7808 PetscInt foffsets[32], coffsets[32]; 7809 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7810 DMPolytopeType ct; 7811 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7812 7813 PetscFunctionBegin; 7814 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7815 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7816 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7817 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7818 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7819 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7820 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7821 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7822 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7823 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7824 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7825 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7826 PetscCall(PetscArrayzero(foffsets, 32)); 7827 PetscCall(PetscArrayzero(coffsets, 32)); 7828 /* Column indices */ 7829 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7830 maxFPoints = numCPoints; 7831 /* Compress out points not in the section */ 7832 /* TODO: Squeeze out points with 0 dof as well */ 7833 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7834 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7835 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7836 cpoints[q*2] = cpoints[p]; 7837 cpoints[q*2+1] = cpoints[p+1]; 7838 ++q; 7839 } 7840 } 7841 numCPoints = q; 7842 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7843 PetscInt fdof; 7844 7845 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7846 if (!dof) continue; 7847 for (f = 0; f < numFields; ++f) { 7848 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7849 coffsets[f+1] += fdof; 7850 } 7851 numCIndices += dof; 7852 } 7853 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7854 /* Row indices */ 7855 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7856 { 7857 DMPlexTransform tr; 7858 DMPolytopeType *rct; 7859 PetscInt *rsize, *rcone, *rornt, Nt; 7860 7861 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7862 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7863 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7864 numSubcells = rsize[Nt-1]; 7865 PetscCall(DMPlexTransformDestroy(&tr)); 7866 } 7867 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7868 for (r = 0, q = 0; r < numSubcells; ++r) { 7869 /* TODO Map from coarse to fine cells */ 7870 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7871 /* Compress out points not in the section */ 7872 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7873 for (p = 0; p < numFPoints*2; p += 2) { 7874 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7875 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7876 if (!dof) continue; 7877 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7878 if (s < q) continue; 7879 ftotpoints[q*2] = fpoints[p]; 7880 ftotpoints[q*2+1] = fpoints[p+1]; 7881 ++q; 7882 } 7883 } 7884 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7885 } 7886 numFPoints = q; 7887 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7888 PetscInt fdof; 7889 7890 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7891 if (!dof) continue; 7892 for (f = 0; f < numFields; ++f) { 7893 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7894 foffsets[f+1] += fdof; 7895 } 7896 numFIndices += dof; 7897 } 7898 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7899 7900 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7901 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7902 if (numFields) { 7903 const PetscInt **permsF[32] = {NULL}; 7904 const PetscInt **permsC[32] = {NULL}; 7905 7906 for (f = 0; f < numFields; f++) { 7907 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7908 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7909 } 7910 for (p = 0; p < numFPoints; p++) { 7911 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7912 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7913 } 7914 for (p = 0; p < numCPoints; p++) { 7915 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7916 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7917 } 7918 for (f = 0; f < numFields; f++) { 7919 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7920 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7921 } 7922 } else { 7923 const PetscInt **permsF = NULL; 7924 const PetscInt **permsC = NULL; 7925 7926 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7927 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7928 for (p = 0, off = 0; p < numFPoints; p++) { 7929 const PetscInt *perm = permsF ? permsF[p] : NULL; 7930 7931 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7932 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7933 } 7934 for (p = 0, off = 0; p < numCPoints; p++) { 7935 const PetscInt *perm = permsC ? permsC[p] : NULL; 7936 7937 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7938 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7939 } 7940 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7941 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7942 } 7943 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7944 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7945 PetscFunctionReturn(0); 7946 } 7947 7948 /*@C 7949 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7950 7951 Input Parameter: 7952 . dm - The DMPlex object 7953 7954 Output Parameter: 7955 . cellHeight - The height of a cell 7956 7957 Level: developer 7958 7959 .seealso `DMPlexSetVTKCellHeight()` 7960 @*/ 7961 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7962 { 7963 DM_Plex *mesh = (DM_Plex*) dm->data; 7964 7965 PetscFunctionBegin; 7966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7967 PetscValidIntPointer(cellHeight, 2); 7968 *cellHeight = mesh->vtkCellHeight; 7969 PetscFunctionReturn(0); 7970 } 7971 7972 /*@C 7973 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7974 7975 Input Parameters: 7976 + dm - The DMPlex object 7977 - cellHeight - The height of a cell 7978 7979 Level: developer 7980 7981 .seealso `DMPlexGetVTKCellHeight()` 7982 @*/ 7983 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7984 { 7985 DM_Plex *mesh = (DM_Plex*) dm->data; 7986 7987 PetscFunctionBegin; 7988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7989 mesh->vtkCellHeight = cellHeight; 7990 PetscFunctionReturn(0); 7991 } 7992 7993 /*@ 7994 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7995 7996 Input Parameter: 7997 . dm - The DMPlex object 7998 7999 Output Parameters: 8000 + gcStart - The first ghost cell, or NULL 8001 - gcEnd - The upper bound on ghost cells, or NULL 8002 8003 Level: advanced 8004 8005 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8006 @*/ 8007 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8008 { 8009 DMLabel ctLabel; 8010 8011 PetscFunctionBegin; 8012 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8013 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8014 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8015 // Reset label for fast lookup 8016 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8017 PetscFunctionReturn(0); 8018 } 8019 8020 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8021 { 8022 PetscSection section, globalSection; 8023 PetscInt *numbers, p; 8024 8025 PetscFunctionBegin; 8026 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8027 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8028 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8029 for (p = pStart; p < pEnd; ++p) { 8030 PetscCall(PetscSectionSetDof(section, p, 1)); 8031 } 8032 PetscCall(PetscSectionSetUp(section)); 8033 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8034 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8035 for (p = pStart; p < pEnd; ++p) { 8036 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8037 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8038 else numbers[p-pStart] += shift; 8039 } 8040 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8041 if (globalSize) { 8042 PetscLayout layout; 8043 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8044 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8045 PetscCall(PetscLayoutDestroy(&layout)); 8046 } 8047 PetscCall(PetscSectionDestroy(§ion)); 8048 PetscCall(PetscSectionDestroy(&globalSection)); 8049 PetscFunctionReturn(0); 8050 } 8051 8052 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8053 { 8054 PetscInt cellHeight, cStart, cEnd; 8055 8056 PetscFunctionBegin; 8057 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8058 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8059 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8060 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8061 PetscFunctionReturn(0); 8062 } 8063 8064 /*@ 8065 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8066 8067 Input Parameter: 8068 . dm - The DMPlex object 8069 8070 Output Parameter: 8071 . globalCellNumbers - Global cell numbers for all cells on this process 8072 8073 Level: developer 8074 8075 .seealso `DMPlexGetVertexNumbering()` 8076 @*/ 8077 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8078 { 8079 DM_Plex *mesh = (DM_Plex*) dm->data; 8080 8081 PetscFunctionBegin; 8082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8083 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8084 *globalCellNumbers = mesh->globalCellNumbers; 8085 PetscFunctionReturn(0); 8086 } 8087 8088 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8089 { 8090 PetscInt vStart, vEnd; 8091 8092 PetscFunctionBegin; 8093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8094 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8095 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8096 PetscFunctionReturn(0); 8097 } 8098 8099 /*@ 8100 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8101 8102 Input Parameter: 8103 . dm - The DMPlex object 8104 8105 Output Parameter: 8106 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8107 8108 Level: developer 8109 8110 .seealso `DMPlexGetCellNumbering()` 8111 @*/ 8112 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8113 { 8114 DM_Plex *mesh = (DM_Plex*) dm->data; 8115 8116 PetscFunctionBegin; 8117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8118 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8119 *globalVertexNumbers = mesh->globalVertexNumbers; 8120 PetscFunctionReturn(0); 8121 } 8122 8123 /*@ 8124 DMPlexCreatePointNumbering - Create a global numbering for all points. 8125 8126 Collective on dm 8127 8128 Input Parameter: 8129 . dm - The DMPlex object 8130 8131 Output Parameter: 8132 . globalPointNumbers - Global numbers for all points on this process 8133 8134 Notes: 8135 8136 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8137 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8138 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8139 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8140 8141 The partitioned mesh is 8142 ``` 8143 (2)--0--(3)--1--(4) (1)--0--(2) 8144 ``` 8145 and its global numbering is 8146 ``` 8147 (3)--0--(4)--1--(5)--2--(6) 8148 ``` 8149 Then the global numbering is provided as 8150 ``` 8151 [0] Number of indices in set 5 8152 [0] 0 0 8153 [0] 1 1 8154 [0] 2 3 8155 [0] 3 4 8156 [0] 4 -6 8157 [1] Number of indices in set 3 8158 [1] 0 2 8159 [1] 1 5 8160 [1] 2 6 8161 ``` 8162 8163 Level: developer 8164 8165 .seealso `DMPlexGetCellNumbering()` 8166 @*/ 8167 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8168 { 8169 IS nums[4]; 8170 PetscInt depths[4], gdepths[4], starts[4]; 8171 PetscInt depth, d, shift = 0; 8172 8173 PetscFunctionBegin; 8174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8175 PetscCall(DMPlexGetDepth(dm, &depth)); 8176 /* For unstratified meshes use dim instead of depth */ 8177 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8178 for (d = 0; d <= depth; ++d) { 8179 PetscInt end; 8180 8181 depths[d] = depth-d; 8182 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8183 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8184 } 8185 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8186 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8187 for (d = 0; d <= depth; ++d) { 8188 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]); 8189 } 8190 for (d = 0; d <= depth; ++d) { 8191 PetscInt pStart, pEnd, gsize; 8192 8193 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8194 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8195 shift += gsize; 8196 } 8197 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8198 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8199 PetscFunctionReturn(0); 8200 } 8201 8202 /*@ 8203 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8204 8205 Input Parameter: 8206 . dm - The DMPlex object 8207 8208 Output Parameter: 8209 . ranks - The rank field 8210 8211 Options Database Keys: 8212 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8213 8214 Level: intermediate 8215 8216 .seealso: `DMView()` 8217 @*/ 8218 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8219 { 8220 DM rdm; 8221 PetscFE fe; 8222 PetscScalar *r; 8223 PetscMPIInt rank; 8224 DMPolytopeType ct; 8225 PetscInt dim, cStart, cEnd, c; 8226 PetscBool simplex; 8227 8228 PetscFunctionBeginUser; 8229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8230 PetscValidPointer(ranks, 2); 8231 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8232 PetscCall(DMClone(dm, &rdm)); 8233 PetscCall(DMGetDimension(rdm, &dim)); 8234 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8235 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8236 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8237 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8238 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8239 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8240 PetscCall(PetscFEDestroy(&fe)); 8241 PetscCall(DMCreateDS(rdm)); 8242 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8243 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8244 PetscCall(VecGetArray(*ranks, &r)); 8245 for (c = cStart; c < cEnd; ++c) { 8246 PetscScalar *lr; 8247 8248 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8249 if (lr) *lr = rank; 8250 } 8251 PetscCall(VecRestoreArray(*ranks, &r)); 8252 PetscCall(DMDestroy(&rdm)); 8253 PetscFunctionReturn(0); 8254 } 8255 8256 /*@ 8257 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8258 8259 Input Parameters: 8260 + dm - The DMPlex 8261 - label - The DMLabel 8262 8263 Output Parameter: 8264 . val - The label value field 8265 8266 Options Database Keys: 8267 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8268 8269 Level: intermediate 8270 8271 .seealso: `DMView()` 8272 @*/ 8273 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8274 { 8275 DM rdm; 8276 PetscFE fe; 8277 PetscScalar *v; 8278 PetscInt dim, cStart, cEnd, c; 8279 8280 PetscFunctionBeginUser; 8281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8282 PetscValidPointer(label, 2); 8283 PetscValidPointer(val, 3); 8284 PetscCall(DMClone(dm, &rdm)); 8285 PetscCall(DMGetDimension(rdm, &dim)); 8286 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8287 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8288 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8289 PetscCall(PetscFEDestroy(&fe)); 8290 PetscCall(DMCreateDS(rdm)); 8291 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8292 PetscCall(DMCreateGlobalVector(rdm, val)); 8293 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8294 PetscCall(VecGetArray(*val, &v)); 8295 for (c = cStart; c < cEnd; ++c) { 8296 PetscScalar *lv; 8297 PetscInt cval; 8298 8299 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8300 PetscCall(DMLabelGetValue(label, c, &cval)); 8301 *lv = cval; 8302 } 8303 PetscCall(VecRestoreArray(*val, &v)); 8304 PetscCall(DMDestroy(&rdm)); 8305 PetscFunctionReturn(0); 8306 } 8307 8308 /*@ 8309 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8310 8311 Input Parameter: 8312 . dm - The DMPlex object 8313 8314 Notes: 8315 This is a useful diagnostic when creating meshes programmatically. 8316 8317 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8318 8319 Level: developer 8320 8321 .seealso: `DMCreate()`, `DMSetFromOptions()` 8322 @*/ 8323 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8324 { 8325 PetscSection coneSection, supportSection; 8326 const PetscInt *cone, *support; 8327 PetscInt coneSize, c, supportSize, s; 8328 PetscInt pStart, pEnd, p, pp, csize, ssize; 8329 PetscBool storagecheck = PETSC_TRUE; 8330 8331 PetscFunctionBegin; 8332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8333 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8334 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8335 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8336 /* Check that point p is found in the support of its cone points, and vice versa */ 8337 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8338 for (p = pStart; p < pEnd; ++p) { 8339 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8340 PetscCall(DMPlexGetCone(dm, p, &cone)); 8341 for (c = 0; c < coneSize; ++c) { 8342 PetscBool dup = PETSC_FALSE; 8343 PetscInt d; 8344 for (d = c-1; d >= 0; --d) { 8345 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8346 } 8347 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8348 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8349 for (s = 0; s < supportSize; ++s) { 8350 if (support[s] == p) break; 8351 } 8352 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8353 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8354 for (s = 0; s < coneSize; ++s) { 8355 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8356 } 8357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8358 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8359 for (s = 0; s < supportSize; ++s) { 8360 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8361 } 8362 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8363 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]); 8364 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8365 } 8366 } 8367 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8368 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8369 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8370 PetscCall(DMPlexGetSupport(dm, p, &support)); 8371 for (s = 0; s < supportSize; ++s) { 8372 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8373 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8374 for (c = 0; c < coneSize; ++c) { 8375 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8376 if (cone[c] != pp) { c = 0; break; } 8377 if (cone[c] == p) break; 8378 } 8379 if (c >= coneSize) { 8380 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8381 for (c = 0; c < supportSize; ++c) { 8382 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8383 } 8384 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8385 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8386 for (c = 0; c < coneSize; ++c) { 8387 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8388 } 8389 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8390 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8391 } 8392 } 8393 } 8394 if (storagecheck) { 8395 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8396 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8397 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8398 } 8399 PetscFunctionReturn(0); 8400 } 8401 8402 /* 8403 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. 8404 */ 8405 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8406 { 8407 DMPolytopeType cct; 8408 PetscInt ptpoints[4]; 8409 const PetscInt *cone, *ccone, *ptcone; 8410 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8411 8412 PetscFunctionBegin; 8413 *unsplit = 0; 8414 switch (ct) { 8415 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8416 ptpoints[npt++] = c; 8417 break; 8418 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8419 PetscCall(DMPlexGetCone(dm, c, &cone)); 8420 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8421 for (cp = 0; cp < coneSize; ++cp) { 8422 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8423 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8424 } 8425 break; 8426 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8427 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8428 PetscCall(DMPlexGetCone(dm, c, &cone)); 8429 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8430 for (cp = 0; cp < coneSize; ++cp) { 8431 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8432 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8433 for (ccp = 0; ccp < cconeSize; ++ccp) { 8434 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8435 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8436 PetscInt p; 8437 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8438 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8439 } 8440 } 8441 } 8442 break; 8443 default: break; 8444 } 8445 for (pt = 0; pt < npt; ++pt) { 8446 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8447 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8448 } 8449 PetscFunctionReturn(0); 8450 } 8451 8452 /*@ 8453 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8454 8455 Input Parameters: 8456 + dm - The DMPlex object 8457 - cellHeight - Normally 0 8458 8459 Notes: 8460 This is a useful diagnostic when creating meshes programmatically. 8461 Currently applicable only to homogeneous simplex or tensor meshes. 8462 8463 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8464 8465 Level: developer 8466 8467 .seealso: `DMCreate()`, `DMSetFromOptions()` 8468 @*/ 8469 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8470 { 8471 DMPlexInterpolatedFlag interp; 8472 DMPolytopeType ct; 8473 PetscInt vStart, vEnd, cStart, cEnd, c; 8474 8475 PetscFunctionBegin; 8476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8477 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8478 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8479 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8480 for (c = cStart; c < cEnd; ++c) { 8481 PetscInt *closure = NULL; 8482 PetscInt coneSize, closureSize, cl, Nv = 0; 8483 8484 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8485 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8486 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8487 if (interp == DMPLEX_INTERPOLATED_FULL) { 8488 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8489 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)); 8490 } 8491 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8492 for (cl = 0; cl < closureSize*2; cl += 2) { 8493 const PetscInt p = closure[cl]; 8494 if ((p >= vStart) && (p < vEnd)) ++Nv; 8495 } 8496 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8497 /* Special Case: Tensor faces with identified vertices */ 8498 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8499 PetscInt unsplit; 8500 8501 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8502 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8503 } 8504 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)); 8505 } 8506 PetscFunctionReturn(0); 8507 } 8508 8509 /*@ 8510 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8511 8512 Collective 8513 8514 Input Parameters: 8515 + dm - The DMPlex object 8516 - cellHeight - Normally 0 8517 8518 Notes: 8519 This is a useful diagnostic when creating meshes programmatically. 8520 This routine is only relevant for meshes that are fully interpolated across all ranks. 8521 It will error out if a partially interpolated mesh is given on some rank. 8522 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8523 8524 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8525 8526 Level: developer 8527 8528 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8529 @*/ 8530 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8531 { 8532 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8533 DMPlexInterpolatedFlag interpEnum; 8534 8535 PetscFunctionBegin; 8536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8537 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8538 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8539 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8540 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8541 PetscFunctionReturn(0); 8542 } 8543 8544 PetscCall(DMGetDimension(dm, &dim)); 8545 PetscCall(DMPlexGetDepth(dm, &depth)); 8546 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8547 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8548 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8549 for (c = cStart; c < cEnd; ++c) { 8550 const PetscInt *cone, *ornt, *faceSizes, *faces; 8551 const DMPolytopeType *faceTypes; 8552 DMPolytopeType ct; 8553 PetscInt numFaces, coneSize, f; 8554 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8555 8556 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8557 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8558 if (unsplit) continue; 8559 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8560 PetscCall(DMPlexGetCone(dm, c, &cone)); 8561 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8562 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8563 for (cl = 0; cl < closureSize*2; cl += 2) { 8564 const PetscInt p = closure[cl]; 8565 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8566 } 8567 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8568 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); 8569 for (f = 0; f < numFaces; ++f) { 8570 DMPolytopeType fct; 8571 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8572 8573 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8574 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8575 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8576 const PetscInt p = fclosure[cl]; 8577 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8578 } 8579 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]); 8580 for (v = 0; v < fnumCorners; ++v) { 8581 if (fclosure[v] != faces[fOff+v]) { 8582 PetscInt v1; 8583 8584 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8585 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8586 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8587 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8588 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8589 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]); 8590 } 8591 } 8592 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8593 fOff += faceSizes[f]; 8594 } 8595 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8596 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8597 } 8598 } 8599 PetscFunctionReturn(0); 8600 } 8601 8602 /*@ 8603 DMPlexCheckGeometry - Check the geometry of mesh cells 8604 8605 Input Parameter: 8606 . dm - The DMPlex object 8607 8608 Notes: 8609 This is a useful diagnostic when creating meshes programmatically. 8610 8611 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8612 8613 Level: developer 8614 8615 .seealso: `DMCreate()`, `DMSetFromOptions()` 8616 @*/ 8617 PetscErrorCode DMPlexCheckGeometry(DM dm) 8618 { 8619 Vec coordinates; 8620 PetscReal detJ, J[9], refVol = 1.0; 8621 PetscReal vol; 8622 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8623 8624 PetscFunctionBegin; 8625 PetscCall(DMGetDimension(dm, &dim)); 8626 PetscCall(DMGetCoordinateDim(dm, &dE)); 8627 if (dim != dE) PetscFunctionReturn(0); 8628 PetscCall(DMPlexGetDepth(dm, &depth)); 8629 for (d = 0; d < dim; ++d) refVol *= 2.0; 8630 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8631 /* Make sure local coordinates are created, because that step is collective */ 8632 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8633 for (c = cStart; c < cEnd; ++c) { 8634 DMPolytopeType ct; 8635 PetscInt unsplit; 8636 PetscBool ignoreZeroVol = PETSC_FALSE; 8637 8638 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8639 switch (ct) { 8640 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8641 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8642 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8643 ignoreZeroVol = PETSC_TRUE; break; 8644 default: break; 8645 } 8646 switch (ct) { 8647 case DM_POLYTOPE_TRI_PRISM: 8648 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8649 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8650 case DM_POLYTOPE_PYRAMID: 8651 continue; 8652 default: break; 8653 } 8654 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8655 if (unsplit) continue; 8656 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8657 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); 8658 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8659 /* This should work with periodicity since DG coordinates should be used */ 8660 if (depth > 1) { 8661 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8662 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); 8663 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8664 } 8665 } 8666 PetscFunctionReturn(0); 8667 } 8668 8669 /*@ 8670 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8671 8672 Collective 8673 8674 Input Parameters: 8675 + dm - The DMPlex object 8676 - pointSF - The Point SF, or NULL for Point SF attached to DM 8677 8678 Notes: 8679 This is mainly intended for debugging/testing purposes. 8680 8681 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8682 8683 Level: developer 8684 8685 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8686 @*/ 8687 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8688 { 8689 PetscInt l, nleaves, nroots, overlap; 8690 const PetscInt *locals; 8691 const PetscSFNode *remotes; 8692 PetscBool distributed; 8693 MPI_Comm comm; 8694 PetscMPIInt rank; 8695 8696 PetscFunctionBegin; 8697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8698 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8699 else pointSF = dm->sf; 8700 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8701 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8702 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8703 { 8704 PetscMPIInt mpiFlag; 8705 8706 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8707 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8708 } 8709 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8710 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8711 if (!distributed) { 8712 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); 8713 PetscFunctionReturn(0); 8714 } 8715 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); 8716 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8717 8718 /* Check SF graph is compatible with DMPlex chart */ 8719 { 8720 PetscInt pStart, pEnd, maxLeaf; 8721 8722 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8723 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8724 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8725 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8726 } 8727 8728 /* Check Point SF has no local points referenced */ 8729 for (l = 0; l < nleaves; l++) { 8730 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); 8731 } 8732 8733 /* Check there are no cells in interface */ 8734 if (!overlap) { 8735 PetscInt cellHeight, cStart, cEnd; 8736 8737 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8738 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8739 for (l = 0; l < nleaves; ++l) { 8740 const PetscInt point = locals ? locals[l] : l; 8741 8742 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8743 } 8744 } 8745 8746 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8747 { 8748 const PetscInt *rootdegree; 8749 8750 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8751 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8752 for (l = 0; l < nleaves; ++l) { 8753 const PetscInt point = locals ? locals[l] : l; 8754 const PetscInt *cone; 8755 PetscInt coneSize, c, idx; 8756 8757 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8758 PetscCall(DMPlexGetCone(dm, point, &cone)); 8759 for (c = 0; c < coneSize; ++c) { 8760 if (!rootdegree[cone[c]]) { 8761 if (locals) { 8762 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8763 } else { 8764 idx = (cone[c] < nleaves) ? cone[c] : -1; 8765 } 8766 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8767 } 8768 } 8769 } 8770 } 8771 PetscFunctionReturn(0); 8772 } 8773 8774 /*@ 8775 DMPlexCheck - Perform various checks of Plex sanity 8776 8777 Input Parameter: 8778 . dm - The DMPlex object 8779 8780 Notes: 8781 This is a useful diagnostic when creating meshes programmatically. 8782 8783 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8784 8785 Currently does not include DMPlexCheckCellShape(). 8786 8787 Level: developer 8788 8789 .seealso: DMCreate(), DMSetFromOptions() 8790 @*/ 8791 PetscErrorCode DMPlexCheck(DM dm) 8792 { 8793 PetscInt cellHeight; 8794 8795 PetscFunctionBegin; 8796 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8797 PetscCall(DMPlexCheckSymmetry(dm)); 8798 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8799 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8800 PetscCall(DMPlexCheckGeometry(dm)); 8801 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8802 PetscCall(DMPlexCheckInterfaceCones(dm)); 8803 PetscFunctionReturn(0); 8804 } 8805 8806 typedef struct cell_stats 8807 { 8808 PetscReal min, max, sum, squaresum; 8809 PetscInt count; 8810 } cell_stats_t; 8811 8812 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8813 { 8814 PetscInt i, N = *len; 8815 8816 for (i = 0; i < N; i++) { 8817 cell_stats_t *A = (cell_stats_t *) a; 8818 cell_stats_t *B = (cell_stats_t *) b; 8819 8820 B->min = PetscMin(A->min,B->min); 8821 B->max = PetscMax(A->max,B->max); 8822 B->sum += A->sum; 8823 B->squaresum += A->squaresum; 8824 B->count += A->count; 8825 } 8826 } 8827 8828 /*@ 8829 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8830 8831 Collective on dm 8832 8833 Input Parameters: 8834 + dm - The DMPlex object 8835 . output - If true, statistics will be displayed on stdout 8836 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8837 8838 Notes: 8839 This is mainly intended for debugging/testing purposes. 8840 8841 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8842 8843 Level: developer 8844 8845 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8846 @*/ 8847 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8848 { 8849 DM dmCoarse; 8850 cell_stats_t stats, globalStats; 8851 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8852 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8853 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8854 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8855 PetscMPIInt rank,size; 8856 8857 PetscFunctionBegin; 8858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8859 stats.min = PETSC_MAX_REAL; 8860 stats.max = PETSC_MIN_REAL; 8861 stats.sum = stats.squaresum = 0.; 8862 stats.count = 0; 8863 8864 PetscCallMPI(MPI_Comm_size(comm, &size)); 8865 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8866 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8867 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8868 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8869 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8870 for (c = cStart; c < cEnd; c++) { 8871 PetscInt i; 8872 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8873 8874 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8875 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8876 for (i = 0; i < PetscSqr(cdim); ++i) { 8877 frobJ += J[i] * J[i]; 8878 frobInvJ += invJ[i] * invJ[i]; 8879 } 8880 cond2 = frobJ * frobInvJ; 8881 cond = PetscSqrtReal(cond2); 8882 8883 stats.min = PetscMin(stats.min,cond); 8884 stats.max = PetscMax(stats.max,cond); 8885 stats.sum += cond; 8886 stats.squaresum += cond2; 8887 stats.count++; 8888 if (output && cond > limit) { 8889 PetscSection coordSection; 8890 Vec coordsLocal; 8891 PetscScalar *coords = NULL; 8892 PetscInt Nv, d, clSize, cl, *closure = NULL; 8893 8894 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8895 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8896 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8897 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8898 for (i = 0; i < Nv/cdim; ++i) { 8899 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8900 for (d = 0; d < cdim; ++d) { 8901 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8902 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8903 } 8904 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8905 } 8906 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8907 for (cl = 0; cl < clSize*2; cl += 2) { 8908 const PetscInt edge = closure[cl]; 8909 8910 if ((edge >= eStart) && (edge < eEnd)) { 8911 PetscReal len; 8912 8913 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8914 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8915 } 8916 } 8917 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8918 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8919 } 8920 } 8921 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8922 8923 if (size > 1) { 8924 PetscMPIInt blockLengths[2] = {4,1}; 8925 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8926 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8927 MPI_Op statReduce; 8928 8929 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8930 PetscCallMPI(MPI_Type_commit(&statType)); 8931 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8932 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8933 PetscCallMPI(MPI_Op_free(&statReduce)); 8934 PetscCallMPI(MPI_Type_free(&statType)); 8935 } else { 8936 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8937 } 8938 if (rank == 0) { 8939 count = globalStats.count; 8940 min = globalStats.min; 8941 max = globalStats.max; 8942 mean = globalStats.sum / globalStats.count; 8943 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8944 } 8945 8946 if (output) { 8947 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)); 8948 } 8949 PetscCall(PetscFree2(J,invJ)); 8950 8951 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8952 if (dmCoarse) { 8953 PetscBool isplex; 8954 8955 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8956 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8957 } 8958 PetscFunctionReturn(0); 8959 } 8960 8961 /*@ 8962 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8963 orthogonal quality below given tolerance. 8964 8965 Collective on dm 8966 8967 Input Parameters: 8968 + dm - The DMPlex object 8969 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8970 - atol - [0, 1] Absolute tolerance for tagging cells. 8971 8972 Output Parameters: 8973 + OrthQual - Vec containing orthogonal quality per cell 8974 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8975 8976 Options Database Keys: 8977 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8978 supported. 8979 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8980 8981 Notes: 8982 Orthogonal quality is given by the following formula: 8983 8984 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8985 8986 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 8987 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8988 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8989 calculating the cosine of the angle between these vectors. 8990 8991 Orthogonal quality ranges from 1 (best) to 0 (worst). 8992 8993 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8994 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8995 8996 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8997 8998 Level: intermediate 8999 9000 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9001 @*/ 9002 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9003 { 9004 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9005 PetscInt *idx; 9006 PetscScalar *oqVals; 9007 const PetscScalar *cellGeomArr, *faceGeomArr; 9008 PetscReal *ci, *fi, *Ai; 9009 MPI_Comm comm; 9010 Vec cellgeom, facegeom; 9011 DM dmFace, dmCell; 9012 IS glob; 9013 ISLocalToGlobalMapping ltog; 9014 PetscViewer vwr; 9015 9016 PetscFunctionBegin; 9017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9018 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 9019 PetscValidPointer(OrthQual, 4); 9020 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 9021 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9022 PetscCall(DMGetDimension(dm, &nc)); 9023 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9024 { 9025 DMPlexInterpolatedFlag interpFlag; 9026 9027 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9028 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9029 PetscMPIInt rank; 9030 9031 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9032 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9033 } 9034 } 9035 if (OrthQualLabel) { 9036 PetscValidPointer(OrthQualLabel, 5); 9037 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9038 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9039 } else {*OrthQualLabel = NULL;} 9040 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9041 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9042 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9043 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9044 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9045 PetscCall(VecCreate(comm, OrthQual)); 9046 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9047 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9048 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9049 PetscCall(VecSetUp(*OrthQual)); 9050 PetscCall(ISDestroy(&glob)); 9051 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9052 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9053 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9054 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9055 PetscCall(VecGetDM(cellgeom, &dmCell)); 9056 PetscCall(VecGetDM(facegeom, &dmFace)); 9057 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9058 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9059 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9060 PetscInt cellarr[2], *adj = NULL; 9061 PetscScalar *cArr, *fArr; 9062 PetscReal minvalc = 1.0, minvalf = 1.0; 9063 PetscFVCellGeom *cg; 9064 9065 idx[cellIter] = cell-cStart; 9066 cellarr[0] = cell; 9067 /* Make indexing into cellGeom easier */ 9068 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9069 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9070 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9071 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9072 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9073 PetscInt i; 9074 const PetscInt neigh = adj[cellneigh]; 9075 PetscReal normci = 0, normfi = 0, normai = 0; 9076 PetscFVCellGeom *cgneigh; 9077 PetscFVFaceGeom *fg; 9078 9079 /* Don't count ourselves in the neighbor list */ 9080 if (neigh == cell) continue; 9081 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9082 cellarr[1] = neigh; 9083 { 9084 PetscInt numcovpts; 9085 const PetscInt *covpts; 9086 9087 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9088 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9089 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9090 } 9091 9092 /* Compute c_i, f_i and their norms */ 9093 for (i = 0; i < nc; i++) { 9094 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9095 fi[i] = fg->centroid[i] - cg->centroid[i]; 9096 Ai[i] = fg->normal[i]; 9097 normci += PetscPowReal(ci[i], 2); 9098 normfi += PetscPowReal(fi[i], 2); 9099 normai += PetscPowReal(Ai[i], 2); 9100 } 9101 normci = PetscSqrtReal(normci); 9102 normfi = PetscSqrtReal(normfi); 9103 normai = PetscSqrtReal(normai); 9104 9105 /* Normalize and compute for each face-cell-normal pair */ 9106 for (i = 0; i < nc; i++) { 9107 ci[i] = ci[i]/normci; 9108 fi[i] = fi[i]/normfi; 9109 Ai[i] = Ai[i]/normai; 9110 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9111 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9112 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9113 } 9114 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9115 minvalc = PetscRealPart(cArr[cellneighiter]); 9116 } 9117 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9118 minvalf = PetscRealPart(fArr[cellneighiter]); 9119 } 9120 } 9121 PetscCall(PetscFree(adj)); 9122 PetscCall(PetscFree2(cArr, fArr)); 9123 /* Defer to cell if they're equal */ 9124 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9125 if (OrthQualLabel) { 9126 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9127 } 9128 } 9129 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9130 PetscCall(VecAssemblyBegin(*OrthQual)); 9131 PetscCall(VecAssemblyEnd(*OrthQual)); 9132 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9133 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9134 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9135 if (OrthQualLabel) { 9136 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9137 } 9138 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9139 PetscCall(PetscViewerDestroy(&vwr)); 9140 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9141 PetscFunctionReturn(0); 9142 } 9143 9144 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9145 * interpolator construction */ 9146 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9147 { 9148 PetscSection section, newSection, gsection; 9149 PetscSF sf; 9150 PetscBool hasConstraints, ghasConstraints; 9151 9152 PetscFunctionBegin; 9153 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9154 PetscValidPointer(odm,2); 9155 PetscCall(DMGetLocalSection(dm, §ion)); 9156 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9157 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9158 if (!ghasConstraints) { 9159 PetscCall(PetscObjectReference((PetscObject)dm)); 9160 *odm = dm; 9161 PetscFunctionReturn(0); 9162 } 9163 PetscCall(DMClone(dm, odm)); 9164 PetscCall(DMCopyFields(dm, *odm)); 9165 PetscCall(DMGetLocalSection(*odm, &newSection)); 9166 PetscCall(DMGetPointSF(*odm, &sf)); 9167 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9168 PetscCall(DMSetGlobalSection(*odm, gsection)); 9169 PetscCall(PetscSectionDestroy(&gsection)); 9170 PetscFunctionReturn(0); 9171 } 9172 9173 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9174 { 9175 DM dmco, dmfo; 9176 Mat interpo; 9177 Vec rscale; 9178 Vec cglobalo, clocal; 9179 Vec fglobal, fglobalo, flocal; 9180 PetscBool regular; 9181 9182 PetscFunctionBegin; 9183 PetscCall(DMGetFullDM(dmc, &dmco)); 9184 PetscCall(DMGetFullDM(dmf, &dmfo)); 9185 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9186 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9187 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9188 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9189 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9190 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9191 PetscCall(VecSet(cglobalo, 0.)); 9192 PetscCall(VecSet(clocal, 0.)); 9193 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9194 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9195 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9196 PetscCall(VecSet(fglobal, 0.)); 9197 PetscCall(VecSet(fglobalo, 0.)); 9198 PetscCall(VecSet(flocal, 0.)); 9199 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9200 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9201 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9202 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9203 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9204 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9205 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9206 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9207 *shift = fglobal; 9208 PetscCall(VecDestroy(&flocal)); 9209 PetscCall(VecDestroy(&fglobalo)); 9210 PetscCall(VecDestroy(&clocal)); 9211 PetscCall(VecDestroy(&cglobalo)); 9212 PetscCall(VecDestroy(&rscale)); 9213 PetscCall(MatDestroy(&interpo)); 9214 PetscCall(DMDestroy(&dmfo)); 9215 PetscCall(DMDestroy(&dmco)); 9216 PetscFunctionReturn(0); 9217 } 9218 9219 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9220 { 9221 PetscObject shifto; 9222 Vec shift; 9223 9224 PetscFunctionBegin; 9225 if (!interp) { 9226 Vec rscale; 9227 9228 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9229 PetscCall(VecDestroy(&rscale)); 9230 } else { 9231 PetscCall(PetscObjectReference((PetscObject)interp)); 9232 } 9233 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9234 if (!shifto) { 9235 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9236 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9237 shifto = (PetscObject) shift; 9238 PetscCall(VecDestroy(&shift)); 9239 } 9240 shift = (Vec) shifto; 9241 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9242 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9243 PetscCall(MatDestroy(&interp)); 9244 PetscFunctionReturn(0); 9245 } 9246 9247 /* Pointwise interpolation 9248 Just code FEM for now 9249 u^f = I u^c 9250 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9251 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9252 I_{ij} = psi^f_i phi^c_j 9253 */ 9254 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9255 { 9256 PetscSection gsc, gsf; 9257 PetscInt m, n; 9258 void *ctx; 9259 DM cdm; 9260 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9261 9262 PetscFunctionBegin; 9263 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9264 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9265 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9266 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9267 9268 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9269 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9270 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9271 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9272 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9273 9274 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9275 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9276 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9277 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9278 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9279 if (scaling) { 9280 /* Use naive scaling */ 9281 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9282 } 9283 PetscFunctionReturn(0); 9284 } 9285 9286 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9287 { 9288 VecScatter ctx; 9289 9290 PetscFunctionBegin; 9291 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9292 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9293 PetscCall(VecScatterDestroy(&ctx)); 9294 PetscFunctionReturn(0); 9295 } 9296 9297 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9298 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9299 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9300 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9301 { 9302 const PetscInt Nc = uOff[1] - uOff[0]; 9303 PetscInt c; 9304 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9305 } 9306 9307 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9308 { 9309 DM dmc; 9310 PetscDS ds; 9311 Vec ones, locmass; 9312 IS cellIS; 9313 PetscFormKey key; 9314 PetscInt depth; 9315 9316 PetscFunctionBegin; 9317 PetscCall(DMClone(dm, &dmc)); 9318 PetscCall(DMCopyDisc(dm, dmc)); 9319 PetscCall(DMGetDS(dmc, &ds)); 9320 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9321 PetscCall(DMCreateGlobalVector(dmc, mass)); 9322 PetscCall(DMGetLocalVector(dmc, &ones)); 9323 PetscCall(DMGetLocalVector(dmc, &locmass)); 9324 PetscCall(DMPlexGetDepth(dmc, &depth)); 9325 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9326 PetscCall(VecSet(locmass, 0.0)); 9327 PetscCall(VecSet(ones, 1.0)); 9328 key.label = NULL; 9329 key.value = 0; 9330 key.field = 0; 9331 key.part = 0; 9332 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9333 PetscCall(ISDestroy(&cellIS)); 9334 PetscCall(VecSet(*mass, 0.0)); 9335 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9336 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9337 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9338 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9339 PetscCall(DMDestroy(&dmc)); 9340 PetscFunctionReturn(0); 9341 } 9342 9343 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9344 { 9345 PetscSection gsc, gsf; 9346 PetscInt m, n; 9347 void *ctx; 9348 DM cdm; 9349 PetscBool regular; 9350 9351 PetscFunctionBegin; 9352 if (dmFine == dmCoarse) { 9353 DM dmc; 9354 PetscDS ds; 9355 PetscWeakForm wf; 9356 Vec u; 9357 IS cellIS; 9358 PetscFormKey key; 9359 PetscInt depth; 9360 9361 PetscCall(DMClone(dmFine, &dmc)); 9362 PetscCall(DMCopyDisc(dmFine, dmc)); 9363 PetscCall(DMGetDS(dmc, &ds)); 9364 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9365 PetscCall(PetscWeakFormClear(wf)); 9366 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9367 PetscCall(DMCreateMatrix(dmc, mass)); 9368 PetscCall(DMGetLocalVector(dmc, &u)); 9369 PetscCall(DMPlexGetDepth(dmc, &depth)); 9370 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9371 PetscCall(MatZeroEntries(*mass)); 9372 key.label = NULL; 9373 key.value = 0; 9374 key.field = 0; 9375 key.part = 0; 9376 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9377 PetscCall(ISDestroy(&cellIS)); 9378 PetscCall(DMRestoreLocalVector(dmc, &u)); 9379 PetscCall(DMDestroy(&dmc)); 9380 } else { 9381 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9382 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9383 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9384 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9385 9386 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9387 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9388 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9389 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9390 9391 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9392 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9393 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9394 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9395 } 9396 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9397 PetscFunctionReturn(0); 9398 } 9399 9400 /*@ 9401 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9402 9403 Input Parameter: 9404 . dm - The DMPlex object 9405 9406 Output Parameter: 9407 . regular - The flag 9408 9409 Level: intermediate 9410 9411 .seealso: `DMPlexSetRegularRefinement()` 9412 @*/ 9413 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9414 { 9415 PetscFunctionBegin; 9416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9417 PetscValidBoolPointer(regular, 2); 9418 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9419 PetscFunctionReturn(0); 9420 } 9421 9422 /*@ 9423 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9424 9425 Input Parameters: 9426 + dm - The DMPlex object 9427 - regular - The flag 9428 9429 Level: intermediate 9430 9431 .seealso: `DMPlexGetRegularRefinement()` 9432 @*/ 9433 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9434 { 9435 PetscFunctionBegin; 9436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9437 ((DM_Plex *) dm->data)->regularRefinement = regular; 9438 PetscFunctionReturn(0); 9439 } 9440 9441 /* anchors */ 9442 /*@ 9443 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9444 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9445 9446 not collective 9447 9448 Input Parameter: 9449 . dm - The DMPlex object 9450 9451 Output Parameters: 9452 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9453 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9454 9455 Level: intermediate 9456 9457 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9458 @*/ 9459 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9460 { 9461 DM_Plex *plex = (DM_Plex *)dm->data; 9462 9463 PetscFunctionBegin; 9464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9465 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9466 if (anchorSection) *anchorSection = plex->anchorSection; 9467 if (anchorIS) *anchorIS = plex->anchorIS; 9468 PetscFunctionReturn(0); 9469 } 9470 9471 /*@ 9472 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9473 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9474 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9475 9476 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9477 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9478 9479 collective on dm 9480 9481 Input Parameters: 9482 + dm - The DMPlex object 9483 . 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). 9484 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9485 9486 The reference counts of anchorSection and anchorIS are incremented. 9487 9488 Level: intermediate 9489 9490 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9491 @*/ 9492 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9493 { 9494 DM_Plex *plex = (DM_Plex *)dm->data; 9495 PetscMPIInt result; 9496 9497 PetscFunctionBegin; 9498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9499 if (anchorSection) { 9500 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9501 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9502 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9503 } 9504 if (anchorIS) { 9505 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9506 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9507 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9508 } 9509 9510 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9511 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9512 plex->anchorSection = anchorSection; 9513 9514 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9515 PetscCall(ISDestroy(&plex->anchorIS)); 9516 plex->anchorIS = anchorIS; 9517 9518 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9519 PetscInt size, a, pStart, pEnd; 9520 const PetscInt *anchors; 9521 9522 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9523 PetscCall(ISGetLocalSize(anchorIS,&size)); 9524 PetscCall(ISGetIndices(anchorIS,&anchors)); 9525 for (a = 0; a < size; a++) { 9526 PetscInt p; 9527 9528 p = anchors[a]; 9529 if (p >= pStart && p < pEnd) { 9530 PetscInt dof; 9531 9532 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9533 if (dof) { 9534 9535 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9536 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9537 } 9538 } 9539 } 9540 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9541 } 9542 /* reset the generic constraints */ 9543 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9544 PetscFunctionReturn(0); 9545 } 9546 9547 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9548 { 9549 PetscSection anchorSection; 9550 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9551 9552 PetscFunctionBegin; 9553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9554 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9555 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9556 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9557 if (numFields) { 9558 PetscInt f; 9559 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9560 9561 for (f = 0; f < numFields; f++) { 9562 PetscInt numComp; 9563 9564 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9565 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9566 } 9567 } 9568 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9569 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9570 pStart = PetscMax(pStart,sStart); 9571 pEnd = PetscMin(pEnd,sEnd); 9572 pEnd = PetscMax(pStart,pEnd); 9573 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9574 for (p = pStart; p < pEnd; p++) { 9575 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9576 if (dof) { 9577 PetscCall(PetscSectionGetDof(section,p,&dof)); 9578 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9579 for (f = 0; f < numFields; f++) { 9580 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9581 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9582 } 9583 } 9584 } 9585 PetscCall(PetscSectionSetUp(*cSec)); 9586 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9587 PetscFunctionReturn(0); 9588 } 9589 9590 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9591 { 9592 PetscSection aSec; 9593 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9594 const PetscInt *anchors; 9595 PetscInt numFields, f; 9596 IS aIS; 9597 MatType mtype; 9598 PetscBool iscuda,iskokkos; 9599 9600 PetscFunctionBegin; 9601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9602 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9603 PetscCall(PetscSectionGetStorageSize(section, &n)); 9604 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9605 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9606 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9607 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9608 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9609 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9610 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9611 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9612 else mtype = MATSEQAIJ; 9613 PetscCall(MatSetType(*cMat,mtype)); 9614 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9615 PetscCall(ISGetIndices(aIS,&anchors)); 9616 /* cSec will be a subset of aSec and section */ 9617 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9618 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9619 PetscCall(PetscMalloc1(m+1,&i)); 9620 i[0] = 0; 9621 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9622 for (p = pStart; p < pEnd; p++) { 9623 PetscInt rDof, rOff, r; 9624 9625 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9626 if (!rDof) continue; 9627 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9628 if (numFields) { 9629 for (f = 0; f < numFields; f++) { 9630 annz = 0; 9631 for (r = 0; r < rDof; r++) { 9632 a = anchors[rOff + r]; 9633 if (a < sStart || a >= sEnd) continue; 9634 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9635 annz += aDof; 9636 } 9637 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9638 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9639 for (q = 0; q < dof; q++) { 9640 i[off + q + 1] = i[off + q] + annz; 9641 } 9642 } 9643 } else { 9644 annz = 0; 9645 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9646 for (q = 0; q < dof; q++) { 9647 a = anchors[rOff + q]; 9648 if (a < sStart || a >= sEnd) continue; 9649 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9650 annz += aDof; 9651 } 9652 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9653 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9654 for (q = 0; q < dof; q++) { 9655 i[off + q + 1] = i[off + q] + annz; 9656 } 9657 } 9658 } 9659 nnz = i[m]; 9660 PetscCall(PetscMalloc1(nnz,&j)); 9661 offset = 0; 9662 for (p = pStart; p < pEnd; p++) { 9663 if (numFields) { 9664 for (f = 0; f < numFields; f++) { 9665 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9666 for (q = 0; q < dof; q++) { 9667 PetscInt rDof, rOff, r; 9668 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9669 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9670 for (r = 0; r < rDof; r++) { 9671 PetscInt s; 9672 9673 a = anchors[rOff + r]; 9674 if (a < sStart || a >= sEnd) continue; 9675 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9676 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9677 for (s = 0; s < aDof; s++) { 9678 j[offset++] = aOff + s; 9679 } 9680 } 9681 } 9682 } 9683 } else { 9684 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9685 for (q = 0; q < dof; q++) { 9686 PetscInt rDof, rOff, r; 9687 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9688 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9689 for (r = 0; r < rDof; r++) { 9690 PetscInt s; 9691 9692 a = anchors[rOff + r]; 9693 if (a < sStart || a >= sEnd) continue; 9694 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9695 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9696 for (s = 0; s < aDof; s++) { 9697 j[offset++] = aOff + s; 9698 } 9699 } 9700 } 9701 } 9702 } 9703 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9704 PetscCall(PetscFree(i)); 9705 PetscCall(PetscFree(j)); 9706 PetscCall(ISRestoreIndices(aIS,&anchors)); 9707 PetscFunctionReturn(0); 9708 } 9709 9710 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9711 { 9712 DM_Plex *plex = (DM_Plex *)dm->data; 9713 PetscSection anchorSection, section, cSec; 9714 Mat cMat; 9715 9716 PetscFunctionBegin; 9717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9718 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9719 if (anchorSection) { 9720 PetscInt Nf; 9721 9722 PetscCall(DMGetLocalSection(dm,§ion)); 9723 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9724 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9725 PetscCall(DMGetNumFields(dm,&Nf)); 9726 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9727 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9728 PetscCall(PetscSectionDestroy(&cSec)); 9729 PetscCall(MatDestroy(&cMat)); 9730 } 9731 PetscFunctionReturn(0); 9732 } 9733 9734 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9735 { 9736 IS subis; 9737 PetscSection section, subsection; 9738 9739 PetscFunctionBegin; 9740 PetscCall(DMGetLocalSection(dm, §ion)); 9741 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9742 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9743 /* Create subdomain */ 9744 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9745 /* Create submodel */ 9746 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9747 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9748 PetscCall(DMSetLocalSection(*subdm, subsection)); 9749 PetscCall(PetscSectionDestroy(&subsection)); 9750 PetscCall(DMCopyDisc(dm, *subdm)); 9751 /* Create map from submodel to global model */ 9752 if (is) { 9753 PetscSection sectionGlobal, subsectionGlobal; 9754 IS spIS; 9755 const PetscInt *spmap; 9756 PetscInt *subIndices; 9757 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9758 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9759 9760 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9761 PetscCall(ISGetIndices(spIS, &spmap)); 9762 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9763 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9764 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9765 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9766 for (p = pStart; p < pEnd; ++p) { 9767 PetscInt gdof, pSubSize = 0; 9768 9769 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9770 if (gdof > 0) { 9771 for (f = 0; f < Nf; ++f) { 9772 PetscInt fdof, fcdof; 9773 9774 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9775 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9776 pSubSize += fdof-fcdof; 9777 } 9778 subSize += pSubSize; 9779 if (pSubSize) { 9780 if (bs < 0) { 9781 bs = pSubSize; 9782 } else if (bs != pSubSize) { 9783 /* Layout does not admit a pointwise block size */ 9784 bs = 1; 9785 } 9786 } 9787 } 9788 } 9789 /* Must have same blocksize on all procs (some might have no points) */ 9790 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9791 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9792 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9793 else {bs = bsMinMax[0];} 9794 PetscCall(PetscMalloc1(subSize, &subIndices)); 9795 for (p = pStart; p < pEnd; ++p) { 9796 PetscInt gdof, goff; 9797 9798 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9799 if (gdof > 0) { 9800 const PetscInt point = spmap[p]; 9801 9802 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9803 for (f = 0; f < Nf; ++f) { 9804 PetscInt fdof, fcdof, fc, f2, poff = 0; 9805 9806 /* Can get rid of this loop by storing field information in the global section */ 9807 for (f2 = 0; f2 < f; ++f2) { 9808 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9809 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9810 poff += fdof-fcdof; 9811 } 9812 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9813 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9814 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9815 subIndices[subOff] = goff+poff+fc; 9816 } 9817 } 9818 } 9819 } 9820 PetscCall(ISRestoreIndices(spIS, &spmap)); 9821 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9822 if (bs > 1) { 9823 /* We need to check that the block size does not come from non-contiguous fields */ 9824 PetscInt i, j, set = 1; 9825 for (i = 0; i < subSize; i += bs) { 9826 for (j = 0; j < bs; ++j) { 9827 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9828 } 9829 } 9830 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9831 } 9832 /* Attach nullspace */ 9833 for (f = 0; f < Nf; ++f) { 9834 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9835 if ((*subdm)->nullspaceConstructors[f]) break; 9836 } 9837 if (f < Nf) { 9838 MatNullSpace nullSpace; 9839 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9840 9841 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9842 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9843 } 9844 } 9845 PetscFunctionReturn(0); 9846 } 9847 9848 /*@ 9849 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9850 9851 Input Parameter: 9852 - dm - The DM 9853 9854 Level: developer 9855 9856 Options Database Keys: 9857 . -dm_plex_monitor_throughput - Activate the monitor 9858 9859 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9860 @*/ 9861 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9862 { 9863 #if defined(PETSC_USE_LOG) 9864 PetscStageLog stageLog; 9865 PetscLogEvent event; 9866 PetscLogStage stage; 9867 PetscEventPerfInfo eventInfo; 9868 PetscReal cellRate, flopRate; 9869 PetscInt cStart, cEnd, Nf, N; 9870 const char *name; 9871 #endif 9872 9873 PetscFunctionBegin; 9874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9875 #if defined(PETSC_USE_LOG) 9876 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9877 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9878 PetscCall(DMGetNumFields(dm, &Nf)); 9879 PetscCall(PetscLogGetStageLog(&stageLog)); 9880 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9881 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9882 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9883 N = (cEnd - cStart)*Nf*eventInfo.count; 9884 flopRate = eventInfo.flops/eventInfo.time; 9885 cellRate = N/eventInfo.time; 9886 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))); 9887 #else 9888 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9889 #endif 9890 PetscFunctionReturn(0); 9891 } 9892