1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph,DMPLEX_RebalRewriteSF,DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 42 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 43 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 44 PetscFunctionReturn(0); 45 } 46 47 /*@ 48 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 49 50 Input Parameters: 51 + dm - The DMPlex object 52 - height - The cell height in the Plex, 0 is the default 53 54 Output Parameters: 55 + cStart - The first "normal" cell 56 - cEnd - The upper bound on "normal"" cells 57 58 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 59 60 Level: developer 61 62 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 63 @*/ 64 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 65 { 66 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 67 PetscInt cS, cE, c; 68 69 PetscFunctionBegin; 70 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 71 for (c = cS; c < cE; ++c) { 72 DMPolytopeType cct; 73 74 PetscCall(DMPlexGetCellType(dm, c, &cct)); 75 if ((PetscInt) cct < 0) break; 76 switch (cct) { 77 case DM_POLYTOPE_POINT: 78 case DM_POLYTOPE_SEGMENT: 79 case DM_POLYTOPE_TRIANGLE: 80 case DM_POLYTOPE_QUADRILATERAL: 81 case DM_POLYTOPE_TETRAHEDRON: 82 case DM_POLYTOPE_HEXAHEDRON: 83 ct = cct; 84 break; 85 default: break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) break; 88 } 89 if (ct != DM_POLYTOPE_UNKNOWN) { 90 DMLabel ctLabel; 91 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 94 // Reset label for fast lookup 95 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 96 } 97 if (cStart) *cStart = cS; 98 if (cEnd) *cEnd = cE; 99 PetscFunctionReturn(0); 100 } 101 102 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 103 { 104 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 105 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 106 107 PetscFunctionBegin; 108 *ft = PETSC_VTK_INVALID; 109 PetscCall(DMGetCoordinateDim(dm, &cdim)); 110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 111 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 112 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 113 if (field >= 0) { 114 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 115 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 116 } else { 117 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 118 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 119 } 120 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 121 if (globalvcdof[0]) { 122 *sStart = vStart; 123 *sEnd = vEnd; 124 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 125 else *ft = PETSC_VTK_POINT_FIELD; 126 } else if (globalvcdof[1]) { 127 *sStart = cStart; 128 *sEnd = cEnd; 129 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 130 else *ft = PETSC_VTK_CELL_FIELD; 131 } else { 132 if (field >= 0) { 133 const char *fieldname; 134 135 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 136 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 137 } else { 138 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 139 } 140 } 141 PetscFunctionReturn(0); 142 } 143 144 /*@ 145 DMPlexVecView1D - Plot many 1D solutions on the same line graph 146 147 Collective on dm 148 149 Input Parameters: 150 + dm - The DMPlex 151 . n - The number of vectors 152 . u - The array of local vectors 153 - viewer - The Draw viewer 154 155 Level: advanced 156 157 .seealso: `VecViewFromOptions()`, `VecView()` 158 @*/ 159 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 160 { 161 PetscDS ds; 162 PetscDraw draw = NULL; 163 PetscDrawLG lg; 164 Vec coordinates; 165 const PetscScalar *coords, **sol; 166 PetscReal *vals; 167 PetscInt *Nc; 168 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 169 char **names; 170 171 PetscFunctionBegin; 172 PetscCall(DMGetDS(dm, &ds)); 173 PetscCall(PetscDSGetNumFields(ds, &Nf)); 174 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 175 PetscCall(PetscDSGetComponents(ds, &Nc)); 176 177 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 178 if (!draw) PetscFunctionReturn(0); 179 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 180 181 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 182 for (i = 0, l = 0; i < n; ++i) { 183 const char *vname; 184 185 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 186 for (f = 0; f < Nf; ++f) { 187 PetscObject disc; 188 const char *fname; 189 char tmpname[PETSC_MAX_PATH_LEN]; 190 191 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 192 /* TODO Create names for components */ 193 for (c = 0; c < Nc[f]; ++c, ++l) { 194 PetscCall(PetscObjectGetName(disc, &fname)); 195 PetscCall(PetscStrcpy(tmpname, vname)); 196 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 197 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 198 PetscCall(PetscStrallocpy(tmpname, &names[l])); 199 } 200 } 201 } 202 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 203 /* Just add P_1 support for now */ 204 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 205 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 206 PetscCall(VecGetArrayRead(coordinates, &coords)); 207 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 208 for (v = vStart; v < vEnd; ++v) { 209 PetscScalar *x, *svals; 210 211 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 212 for (i = 0; i < n; ++i) { 213 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 214 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 215 } 216 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 217 } 218 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 219 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 220 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 221 PetscCall(PetscFree3(sol, names, vals)); 222 223 PetscCall(PetscDrawLGDraw(lg)); 224 PetscCall(PetscDrawLGDestroy(&lg)); 225 PetscFunctionReturn(0); 226 } 227 228 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 229 { 230 DM dm; 231 232 PetscFunctionBegin; 233 PetscCall(VecGetDM(u, &dm)); 234 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 235 PetscFunctionReturn(0); 236 } 237 238 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 239 { 240 DM dm; 241 PetscSection s; 242 PetscDraw draw, popup; 243 DM cdm; 244 PetscSection coordSection; 245 Vec coordinates; 246 const PetscScalar *coords, *array; 247 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 248 PetscReal vbound[2], time; 249 PetscBool flg; 250 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 251 const char *name; 252 char title[PETSC_MAX_PATH_LEN]; 253 254 PetscFunctionBegin; 255 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 256 PetscCall(VecGetDM(v, &dm)); 257 PetscCall(DMGetCoordinateDim(dm, &dim)); 258 PetscCall(DMGetLocalSection(dm, &s)); 259 PetscCall(PetscSectionGetNumFields(s, &Nf)); 260 PetscCall(DMGetCoarsenLevel(dm, &level)); 261 PetscCall(DMGetCoordinateDM(dm, &cdm)); 262 PetscCall(DMGetLocalSection(cdm, &coordSection)); 263 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 264 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 265 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 266 267 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 268 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 269 270 PetscCall(VecGetLocalSize(coordinates, &N)); 271 PetscCall(VecGetArrayRead(coordinates, &coords)); 272 for (c = 0; c < N; c += dim) { 273 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 274 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 275 } 276 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 277 PetscCall(PetscDrawClear(draw)); 278 279 /* Could implement something like DMDASelectFields() */ 280 for (f = 0; f < Nf; ++f) { 281 DM fdm = dm; 282 Vec fv = v; 283 IS fis; 284 char prefix[PETSC_MAX_PATH_LEN]; 285 const char *fname; 286 287 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 288 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 289 290 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 291 else {prefix[0] = '\0';} 292 if (Nf > 1) { 293 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 294 PetscCall(VecGetSubVector(v, fis, &fv)); 295 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 296 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 297 } 298 for (comp = 0; comp < Nc; ++comp, ++w) { 299 PetscInt nmax = 2; 300 301 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 302 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 303 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 304 PetscCall(PetscDrawSetTitle(draw, title)); 305 306 /* TODO Get max and min only for this component */ 307 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 308 if (!flg) { 309 PetscCall(VecMin(fv, NULL, &vbound[0])); 310 PetscCall(VecMax(fv, NULL, &vbound[1])); 311 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 312 } 313 PetscCall(PetscDrawGetPopup(draw, &popup)); 314 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 315 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 316 317 PetscCall(VecGetArrayRead(fv, &array)); 318 for (c = cStart; c < cEnd; ++c) { 319 PetscScalar *coords = NULL, *a = NULL; 320 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 321 322 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 323 if (a) { 324 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 325 color[1] = color[2] = color[3] = color[0]; 326 } else { 327 PetscScalar *vals = NULL; 328 PetscInt numVals, va; 329 330 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 331 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 332 switch (numVals/Nc) { 333 case 3: /* P1 Triangle */ 334 case 4: /* P1 Quadrangle */ 335 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 336 break; 337 case 6: /* P2 Triangle */ 338 case 8: /* P2 Quadrangle */ 339 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 340 break; 341 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 342 } 343 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 344 } 345 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 346 switch (numCoords) { 347 case 6: 348 case 12: /* Localized triangle */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 break; 351 case 8: 352 case 16: /* Localized quadrilateral */ 353 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 354 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 355 break; 356 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 357 } 358 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 359 } 360 PetscCall(VecRestoreArrayRead(fv, &array)); 361 PetscCall(PetscDrawFlush(draw)); 362 PetscCall(PetscDrawPause(draw)); 363 PetscCall(PetscDrawSave(draw)); 364 } 365 if (Nf > 1) { 366 PetscCall(VecRestoreSubVector(v, fis, &fv)); 367 PetscCall(ISDestroy(&fis)); 368 PetscCall(DMDestroy(&fdm)); 369 } 370 } 371 PetscFunctionReturn(0); 372 } 373 374 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 375 { 376 DM dm; 377 PetscDraw draw; 378 PetscInt dim; 379 PetscBool isnull; 380 381 PetscFunctionBegin; 382 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 383 PetscCall(PetscDrawIsNull(draw, &isnull)); 384 if (isnull) PetscFunctionReturn(0); 385 386 PetscCall(VecGetDM(v, &dm)); 387 PetscCall(DMGetCoordinateDim(dm, &dim)); 388 switch (dim) { 389 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 390 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 391 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 397 { 398 DM dm; 399 Vec locv; 400 const char *name; 401 PetscSection section; 402 PetscInt pStart, pEnd; 403 PetscInt numFields; 404 PetscViewerVTKFieldType ft; 405 406 PetscFunctionBegin; 407 PetscCall(VecGetDM(v, &dm)); 408 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 409 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 410 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 411 PetscCall(VecCopy(v, locv)); 412 PetscCall(DMGetLocalSection(dm, §ion)); 413 PetscCall(PetscSectionGetNumFields(section, &numFields)); 414 if (!numFields) { 415 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 416 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 417 } else { 418 PetscInt f; 419 420 for (f = 0; f < numFields; f++) { 421 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 422 if (ft == PETSC_VTK_INVALID) continue; 423 PetscCall(PetscObjectReference((PetscObject)locv)); 424 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 425 } 426 PetscCall(VecDestroy(&locv)); 427 } 428 PetscFunctionReturn(0); 429 } 430 431 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 432 { 433 DM dm; 434 PetscBool isvtk, ishdf5, isdraw, isglvis; 435 436 PetscFunctionBegin; 437 PetscCall(VecGetDM(v, &dm)); 438 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 439 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 440 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 441 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 442 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 443 if (isvtk || ishdf5 || isdraw || isglvis) { 444 PetscInt i,numFields; 445 PetscObject fe; 446 PetscBool fem = PETSC_FALSE; 447 Vec locv = v; 448 const char *name; 449 PetscInt step; 450 PetscReal time; 451 452 PetscCall(DMGetNumFields(dm, &numFields)); 453 for (i=0; i<numFields; i++) { 454 PetscCall(DMGetField(dm, i, NULL, &fe)); 455 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 456 } 457 if (fem) { 458 PetscObject isZero; 459 460 PetscCall(DMGetLocalVector(dm, &locv)); 461 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 462 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 463 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 464 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 465 PetscCall(VecCopy(v, locv)); 466 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 467 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 468 } 469 if (isvtk) { 470 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 471 } else if (ishdf5) { 472 #if defined(PETSC_HAVE_HDF5) 473 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 474 #else 475 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 476 #endif 477 } else if (isdraw) { 478 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 479 } else if (isglvis) { 480 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 481 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 482 PetscCall(VecView_GLVis(locv, viewer)); 483 } 484 if (fem) { 485 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 486 PetscCall(DMRestoreLocalVector(dm, &locv)); 487 } 488 } else { 489 PetscBool isseq; 490 491 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 492 if (isseq) PetscCall(VecView_Seq(v, viewer)); 493 else PetscCall(VecView_MPI(v, viewer)); 494 } 495 PetscFunctionReturn(0); 496 } 497 498 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 499 { 500 DM dm; 501 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 502 503 PetscFunctionBegin; 504 PetscCall(VecGetDM(v, &dm)); 505 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 507 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 508 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 509 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 510 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 511 if (isvtk || isdraw || isglvis) { 512 Vec locv; 513 PetscObject isZero; 514 const char *name; 515 516 PetscCall(DMGetLocalVector(dm, &locv)); 517 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 518 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 519 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 520 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 521 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 522 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 523 PetscCall(VecView_Plex_Local(locv, viewer)); 524 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 525 PetscCall(DMRestoreLocalVector(dm, &locv)); 526 } else if (ishdf5) { 527 #if defined(PETSC_HAVE_HDF5) 528 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 529 #else 530 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 531 #endif 532 } else if (isexodusii) { 533 #if defined(PETSC_HAVE_EXODUSII) 534 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 535 #else 536 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 537 #endif 538 } else { 539 PetscBool isseq; 540 541 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 542 if (isseq) PetscCall(VecView_Seq(v, viewer)); 543 else PetscCall(VecView_MPI(v, viewer)); 544 } 545 PetscFunctionReturn(0); 546 } 547 548 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 549 { 550 DM dm; 551 MPI_Comm comm; 552 PetscViewerFormat format; 553 Vec v; 554 PetscBool isvtk, ishdf5; 555 556 PetscFunctionBegin; 557 PetscCall(VecGetDM(originalv, &dm)); 558 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 559 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 560 PetscCall(PetscViewerGetFormat(viewer, &format)); 561 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 562 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 563 if (format == PETSC_VIEWER_NATIVE) { 564 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 565 /* this need a better fix */ 566 if (dm->useNatural) { 567 if (dm->sfNatural) { 568 const char *vecname; 569 PetscInt n, nroots; 570 571 PetscCall(VecGetLocalSize(originalv, &n)); 572 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 573 if (n == nroots) { 574 PetscCall(DMGetGlobalVector(dm, &v)); 575 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 576 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 577 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 578 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 579 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 580 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 581 } else v = originalv; 582 } else v = originalv; 583 584 if (ishdf5) { 585 #if defined(PETSC_HAVE_HDF5) 586 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 587 #else 588 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 589 #endif 590 } else if (isvtk) { 591 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 592 } else { 593 PetscBool isseq; 594 595 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 596 if (isseq) PetscCall(VecView_Seq(v, viewer)); 597 else PetscCall(VecView_MPI(v, viewer)); 598 } 599 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 600 PetscFunctionReturn(0); 601 } 602 603 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 604 { 605 DM dm; 606 PetscBool ishdf5; 607 608 PetscFunctionBegin; 609 PetscCall(VecGetDM(v, &dm)); 610 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 611 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 612 if (ishdf5) { 613 DM dmBC; 614 Vec gv; 615 const char *name; 616 617 PetscCall(DMGetOutputDM(dm, &dmBC)); 618 PetscCall(DMGetGlobalVector(dmBC, &gv)); 619 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 620 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 621 PetscCall(VecLoad_Default(gv, viewer)); 622 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 623 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 624 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 625 } else PetscCall(VecLoad_Default(v, viewer)); 626 PetscFunctionReturn(0); 627 } 628 629 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool ishdf5,isexodusii; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 638 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (ishdf5) { 640 #if defined(PETSC_HAVE_HDF5) 641 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 642 #else 643 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 644 #endif 645 } else if (isexodusii) { 646 #if defined(PETSC_HAVE_EXODUSII) 647 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 648 #else 649 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 650 #endif 651 } else PetscCall(VecLoad_Default(v, viewer)); 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 692 { 693 PetscSection coordSection; 694 Vec coordinates; 695 DMLabel depthLabel, celltypeLabel; 696 const char *name[4]; 697 const PetscScalar *a; 698 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 699 700 PetscFunctionBegin; 701 PetscCall(DMGetDimension(dm, &dim)); 702 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 703 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 704 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 705 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 706 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 707 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 708 PetscCall(VecGetArrayRead(coordinates, &a)); 709 name[0] = "vertex"; 710 name[1] = "edge"; 711 name[dim-1] = "face"; 712 name[dim] = "cell"; 713 for (c = cStart; c < cEnd; ++c) { 714 PetscInt *closure = NULL; 715 PetscInt closureSize, cl, ct; 716 717 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 718 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 719 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 720 PetscCall(PetscViewerASCIIPushTab(viewer)); 721 for (cl = 0; cl < closureSize*2; cl += 2) { 722 PetscInt point = closure[cl], depth, dof, off, d, p; 723 724 if ((point < pStart) || (point >= pEnd)) continue; 725 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 726 if (!dof) continue; 727 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 728 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 729 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 730 for (p = 0; p < dof/dim; ++p) { 731 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 732 for (d = 0; d < dim; ++d) { 733 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 734 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 735 } 736 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 739 } 740 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 741 PetscCall(PetscViewerASCIIPopTab(viewer)); 742 } 743 PetscCall(VecRestoreArrayRead(coordinates, &a)); 744 PetscFunctionReturn(0); 745 } 746 747 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 748 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 749 750 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 751 { 752 PetscInt i; 753 754 PetscFunctionBegin; 755 if (dim > 3) { 756 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 757 } else { 758 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 759 760 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 761 switch (cs) { 762 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 763 case CS_POLAR: 764 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 765 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 766 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 767 break; 768 case CS_CYLINDRICAL: 769 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 trcoords[2] = coords[2]; 773 break; 774 case CS_SPHERICAL: 775 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 776 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 777 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 778 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 779 break; 780 } 781 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 782 } 783 PetscFunctionReturn(0); 784 } 785 786 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 787 { 788 DM_Plex *mesh = (DM_Plex*) dm->data; 789 DM cdm, cdmCell; 790 PetscSection coordSection, coordSectionCell; 791 Vec coordinates, coordinatesCell; 792 PetscViewerFormat format; 793 794 PetscFunctionBegin; 795 PetscCall(DMGetCoordinateDM(dm, &cdm)); 796 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 797 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 798 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 799 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 800 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 801 PetscCall(PetscViewerGetFormat(viewer, &format)); 802 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 803 const char *name; 804 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 805 PetscInt pStart, pEnd, p, numLabels, l; 806 PetscMPIInt rank, size; 807 808 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 809 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 810 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 811 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 812 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 813 PetscCall(DMGetDimension(dm, &dim)); 814 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 815 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 816 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 817 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 818 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 819 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 820 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 821 for (p = pStart; p < pEnd; ++p) { 822 PetscInt dof, off, s; 823 824 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 825 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 826 for (s = off; s < off+dof; ++s) { 827 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 828 } 829 } 830 PetscCall(PetscViewerFlush(viewer)); 831 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 832 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 833 for (p = pStart; p < pEnd; ++p) { 834 PetscInt dof, off, c; 835 836 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 837 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 838 for (c = off; c < off+dof; ++c) { 839 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 840 } 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize*2; p += 2) { 992 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 993 } 994 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 995 } 996 } 997 } 998 999 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1000 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1001 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1003 \\documentclass[tikz]{standalone}\n\n\ 1004 \\usepackage{pgflibraryshapes}\n\ 1005 \\usetikzlibrary{backgrounds}\n\ 1006 \\usetikzlibrary{arrows}\n\ 1007 \\begin{document}\n")); 1008 if (size > 1) { 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1010 for (p = 0; p < size; ++p) { 1011 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1012 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1013 } 1014 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1015 } 1016 if (drawHasse) { 1017 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1018 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1031 } 1032 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1033 1034 /* Plot vertices */ 1035 PetscCall(VecGetArray(coordinates, &coords)); 1036 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1037 for (v = vStart; v < vEnd; ++v) { 1038 PetscInt off, dof, d; 1039 PetscBool isLabeled = PETSC_FALSE; 1040 1041 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1042 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1043 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1044 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1045 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1046 for (d = 0; d < dof; ++d) { 1047 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1048 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1049 } 1050 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1051 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1052 for (d = 0; d < dof; ++d) { 1053 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1054 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1055 } 1056 if (drawHasse) color = colors[0%numColors]; 1057 else color = colors[rank%numColors]; 1058 for (l = 0; l < numLabels; ++l) { 1059 PetscInt val; 1060 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1061 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1062 } 1063 if (drawNumbers[0]) { 1064 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1065 } else if (drawColors[0]) { 1066 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1067 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1068 } 1069 PetscCall(VecRestoreArray(coordinates, &coords)); 1070 PetscCall(PetscViewerFlush(viewer)); 1071 /* Plot edges */ 1072 if (plotEdges) { 1073 PetscCall(VecGetArray(coordinates, &coords)); 1074 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1075 for (e = eStart; e < eEnd; ++e) { 1076 const PetscInt *cone; 1077 PetscInt coneSize, offA, offB, dof, d; 1078 1079 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1080 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1081 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1082 PetscCall(DMPlexGetCone(dm, e, &cone)); 1083 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1084 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1085 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1086 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1087 for (d = 0; d < dof; ++d) { 1088 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1089 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1090 } 1091 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1092 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1093 for (d = 0; d < dof; ++d) { 1094 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1095 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1096 } 1097 if (drawHasse) color = colors[1%numColors]; 1098 else color = colors[rank%numColors]; 1099 for (l = 0; l < numLabels; ++l) { 1100 PetscInt val; 1101 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1102 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1103 } 1104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1105 } 1106 PetscCall(VecRestoreArray(coordinates, &coords)); 1107 PetscCall(PetscViewerFlush(viewer)); 1108 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1109 } 1110 /* Plot cells */ 1111 if (dim == 3 || !drawNumbers[1]) { 1112 for (e = eStart; e < eEnd; ++e) { 1113 const PetscInt *cone; 1114 1115 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1116 color = colors[rank%numColors]; 1117 for (l = 0; l < numLabels; ++l) { 1118 PetscInt val; 1119 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1120 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1121 } 1122 PetscCall(DMPlexGetCone(dm, e, &cone)); 1123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1124 } 1125 } else { 1126 DMPolytopeType ct; 1127 1128 /* Drawing a 2D polygon */ 1129 for (c = cStart; c < cEnd; ++c) { 1130 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1131 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1132 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1133 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1134 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1135 const PetscInt *cone; 1136 PetscInt coneSize, e; 1137 1138 PetscCall(DMPlexGetCone(dm, c, &cone)); 1139 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1140 for (e = 0; e < coneSize; ++e) { 1141 const PetscInt *econe; 1142 1143 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1144 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1145 } 1146 } else { 1147 PetscInt *closure = NULL; 1148 PetscInt closureSize, Nv = 0, v; 1149 1150 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1151 for (p = 0; p < closureSize*2; p += 2) { 1152 const PetscInt point = closure[p]; 1153 1154 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1155 } 1156 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1157 for (v = 0; v <= Nv; ++v) { 1158 const PetscInt vertex = closure[v%Nv]; 1159 1160 if (v > 0) { 1161 if (plotEdges) { 1162 const PetscInt *edge; 1163 PetscInt endpoints[2], ne; 1164 1165 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1166 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1167 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1168 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1169 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1170 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1171 } 1172 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1173 } 1174 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1175 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1176 } 1177 } 1178 } 1179 for (c = cStart; c < cEnd; ++c) { 1180 double ccoords[3] = {0.0, 0.0, 0.0}; 1181 PetscBool isLabeled = PETSC_FALSE; 1182 PetscScalar *cellCoords = NULL; 1183 const PetscScalar *array; 1184 PetscInt numCoords, cdim, d; 1185 PetscBool isDG; 1186 1187 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1188 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1189 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1190 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1191 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1192 for (p = 0; p < numCoords/cdim; ++p) { 1193 for (d = 0; d < cdim; ++d) { 1194 tcoords[d] = (double) (scale*PetscRealPart(cellCoords[p*cdim+d])); 1195 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1196 } 1197 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1198 if (cdim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1199 for (d = 0; d < dim; ++d) {ccoords[d] += tcoords[d];} 1200 } 1201 for (d = 0; d < cdim; ++d) {ccoords[d] /= (numCoords/cdim);} 1202 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1203 for (d = 0; d < cdim; ++d) { 1204 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1205 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1206 } 1207 if (drawHasse) color = colors[depth%numColors]; 1208 else color = colors[rank%numColors]; 1209 for (l = 0; l < numLabels; ++l) { 1210 PetscInt val; 1211 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1212 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1213 } 1214 if (drawNumbers[dim]) { 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1216 } else if (drawColors[dim]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1219 } 1220 if (drawHasse) { 1221 color = colors[depth%numColors]; 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1226 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1227 1228 color = colors[1%numColors]; 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1234 1235 color = colors[0%numColors]; 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1241 1242 for (p = pStart; p < pEnd; ++p) { 1243 const PetscInt *cone; 1244 PetscInt coneSize, cp; 1245 1246 PetscCall(DMPlexGetCone(dm, p, &cone)); 1247 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1248 for (cp = 0; cp < coneSize; ++cp) { 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1250 } 1251 } 1252 } 1253 PetscCall(PetscViewerFlush(viewer)); 1254 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1257 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1258 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1259 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1260 PetscCall(PetscFree3(names, colors, lcolors)); 1261 PetscCall(PetscBTDestroy(&wp)); 1262 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1263 Vec cown,acown; 1264 VecScatter sct; 1265 ISLocalToGlobalMapping g2l; 1266 IS gid,acis; 1267 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1268 MPI_Group ggroup,ngroup; 1269 PetscScalar *array,nid; 1270 const PetscInt *idxs; 1271 PetscInt *idxs2,*start,*adjacency,*work; 1272 PetscInt64 lm[3],gm[3]; 1273 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1274 PetscMPIInt d1,d2,rank; 1275 1276 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1277 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1278 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1279 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1280 #endif 1281 if (ncomm != MPI_COMM_NULL) { 1282 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1283 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1284 d1 = 0; 1285 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1286 nid = d2; 1287 PetscCallMPI(MPI_Group_free(&ggroup)); 1288 PetscCallMPI(MPI_Group_free(&ngroup)); 1289 PetscCallMPI(MPI_Comm_free(&ncomm)); 1290 } else nid = 0.0; 1291 1292 /* Get connectivity */ 1293 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1294 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1295 1296 /* filter overlapped local cells */ 1297 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1298 PetscCall(ISGetIndices(gid,&idxs)); 1299 PetscCall(ISGetLocalSize(gid,&cum)); 1300 PetscCall(PetscMalloc1(cum,&idxs2)); 1301 for (c = cStart, cum = 0; c < cEnd; c++) { 1302 if (idxs[c-cStart] < 0) continue; 1303 idxs2[cum++] = idxs[c-cStart]; 1304 } 1305 PetscCall(ISRestoreIndices(gid,&idxs)); 1306 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1307 PetscCall(ISDestroy(&gid)); 1308 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1309 1310 /* support for node-aware cell locality */ 1311 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1312 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1313 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1314 PetscCall(VecGetArray(cown,&array)); 1315 for (c = 0; c < numVertices; c++) array[c] = nid; 1316 PetscCall(VecRestoreArray(cown,&array)); 1317 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1318 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1319 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1320 PetscCall(ISDestroy(&acis)); 1321 PetscCall(VecScatterDestroy(&sct)); 1322 PetscCall(VecDestroy(&cown)); 1323 1324 /* compute edgeCut */ 1325 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1326 PetscCall(PetscMalloc1(cum,&work)); 1327 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1328 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1329 PetscCall(ISDestroy(&gid)); 1330 PetscCall(VecGetArray(acown,&array)); 1331 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1332 PetscInt totl; 1333 1334 totl = start[c+1]-start[c]; 1335 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1336 for (i = 0; i < totl; i++) { 1337 if (work[i] < 0) { 1338 ect += 1; 1339 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1340 } 1341 } 1342 } 1343 PetscCall(PetscFree(work)); 1344 PetscCall(VecRestoreArray(acown,&array)); 1345 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1346 lm[1] = -numVertices; 1347 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1348 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1349 lm[0] = ect; /* edgeCut */ 1350 lm[1] = ectn; /* node-aware edgeCut */ 1351 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1352 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1353 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1354 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1355 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1356 #else 1357 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1358 #endif 1359 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1360 PetscCall(PetscFree(start)); 1361 PetscCall(PetscFree(adjacency)); 1362 PetscCall(VecDestroy(&acown)); 1363 } else { 1364 const char *name; 1365 PetscInt *sizes, *hybsizes, *ghostsizes; 1366 PetscInt locDepth, depth, cellHeight, dim, d; 1367 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1368 PetscInt numLabels, l, maxSize = 17; 1369 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1370 MPI_Comm comm; 1371 PetscMPIInt size, rank; 1372 1373 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1374 PetscCallMPI(MPI_Comm_size(comm, &size)); 1375 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1376 PetscCall(DMGetDimension(dm, &dim)); 1377 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1378 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1379 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1380 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1381 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1382 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1383 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1384 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1385 gcNum = gcEnd - gcStart; 1386 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1387 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1388 for (d = 0; d <= depth; d++) { 1389 PetscInt Nc[2] = {0, 0}, ict; 1390 1391 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1392 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1393 ict = ct0; 1394 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1395 ct0 = (DMPolytopeType) ict; 1396 for (p = pStart; p < pEnd; ++p) { 1397 DMPolytopeType ct; 1398 1399 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1400 if (ct == ct0) ++Nc[0]; 1401 else ++Nc[1]; 1402 } 1403 if (size < maxSize) { 1404 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1405 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1406 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1408 for (p = 0; p < size; ++p) { 1409 if (rank == 0) { 1410 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1411 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1412 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1413 } 1414 } 1415 } else { 1416 PetscInt locMinMax[2]; 1417 1418 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1419 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1420 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1421 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1422 if (d == depth) { 1423 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1424 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1425 } 1426 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1427 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1428 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1429 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1430 } 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1432 } 1433 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1434 { 1435 const PetscReal *maxCell; 1436 const PetscReal *L; 1437 PetscBool localized; 1438 1439 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1440 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1441 if (L || localized) { 1442 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1443 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1444 if (L) { 1445 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1446 for (d = 0; d < dim; ++d) { 1447 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1448 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1451 } 1452 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1453 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1454 } 1455 } 1456 PetscCall(DMGetNumLabels(dm, &numLabels)); 1457 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1458 for (l = 0; l < numLabels; ++l) { 1459 DMLabel label; 1460 const char *name; 1461 IS valueIS; 1462 const PetscInt *values; 1463 PetscInt numValues, v; 1464 1465 PetscCall(DMGetLabelName(dm, l, &name)); 1466 PetscCall(DMGetLabel(dm, name, &label)); 1467 PetscCall(DMLabelGetNumValues(label, &numValues)); 1468 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1469 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1470 PetscCall(ISGetIndices(valueIS, &values)); 1471 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1472 for (v = 0; v < numValues; ++v) { 1473 PetscInt size; 1474 1475 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1476 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1477 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1478 } 1479 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1480 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1481 PetscCall(ISRestoreIndices(valueIS, &values)); 1482 PetscCall(ISDestroy(&valueIS)); 1483 } 1484 { 1485 char **labelNames; 1486 PetscInt Nl = numLabels; 1487 PetscBool flg; 1488 1489 PetscCall(PetscMalloc1(Nl, &labelNames)); 1490 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1491 for (l = 0; l < Nl; ++l) { 1492 DMLabel label; 1493 1494 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1495 if (flg) { 1496 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1497 PetscCall(DMLabelView(label, viewer)); 1498 } 1499 PetscCall(PetscFree(labelNames[l])); 1500 } 1501 PetscCall(PetscFree(labelNames)); 1502 } 1503 /* If no fields are specified, people do not want to see adjacency */ 1504 if (dm->Nf) { 1505 PetscInt f; 1506 1507 for (f = 0; f < dm->Nf; ++f) { 1508 const char *name; 1509 1510 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1511 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1512 PetscCall(PetscViewerASCIIPushTab(viewer)); 1513 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1514 if (dm->fields[f].adjacency[0]) { 1515 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1516 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1517 } else { 1518 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1519 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1520 } 1521 PetscCall(PetscViewerASCIIPopTab(viewer)); 1522 } 1523 } 1524 PetscCall(DMGetCoarseDM(dm, &cdm)); 1525 if (cdm) { 1526 PetscCall(PetscViewerASCIIPushTab(viewer)); 1527 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1528 PetscCall(PetscViewerASCIIPopTab(viewer)); 1529 } 1530 } 1531 PetscFunctionReturn(0); 1532 } 1533 1534 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1535 { 1536 DMPolytopeType ct; 1537 PetscMPIInt rank; 1538 PetscInt cdim; 1539 1540 PetscFunctionBegin; 1541 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1542 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1543 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1544 switch (ct) { 1545 case DM_POLYTOPE_SEGMENT: 1546 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1547 switch (cdim) { 1548 case 1: 1549 { 1550 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1551 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1556 } 1557 break; 1558 case 2: 1559 { 1560 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1561 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1562 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1563 1564 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1565 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)); 1566 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)); 1567 } 1568 break; 1569 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1570 } 1571 break; 1572 case DM_POLYTOPE_TRIANGLE: 1573 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1575 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1578 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1580 break; 1581 case DM_POLYTOPE_QUADRILATERAL: 1582 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1583 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1584 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1585 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1586 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1587 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1588 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1589 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1590 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1591 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1592 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1594 break; 1595 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1596 } 1597 PetscFunctionReturn(0); 1598 } 1599 1600 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1601 { 1602 DMPolytopeType ct; 1603 PetscReal centroid[2] = {0., 0.}; 1604 PetscMPIInt rank; 1605 PetscInt fillColor, v, e, d; 1606 1607 PetscFunctionBegin; 1608 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1609 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1610 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1611 switch (ct) { 1612 case DM_POLYTOPE_TRIANGLE: 1613 { 1614 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1615 1616 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1617 for (e = 0; e < 3; ++e) { 1618 refCoords[0] = refVertices[e*2+0]; 1619 refCoords[1] = refVertices[e*2+1]; 1620 for (d = 1; d <= edgeDiv; ++d) { 1621 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1622 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1623 } 1624 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1625 for (d = 0; d < edgeDiv; ++d) { 1626 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)); 1627 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1628 } 1629 } 1630 } 1631 break; 1632 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1633 } 1634 PetscFunctionReturn(0); 1635 } 1636 1637 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1638 { 1639 PetscDraw draw; 1640 DM cdm; 1641 PetscSection coordSection; 1642 Vec coordinates; 1643 const PetscScalar *coords; 1644 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1645 PetscReal *refCoords, *edgeCoords; 1646 PetscBool isnull, drawAffine = PETSC_TRUE; 1647 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1648 1649 PetscFunctionBegin; 1650 PetscCall(DMGetCoordinateDim(dm, &dim)); 1651 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1652 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1653 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1654 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1655 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1656 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1657 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1658 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1659 1660 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1661 PetscCall(PetscDrawIsNull(draw, &isnull)); 1662 if (isnull) PetscFunctionReturn(0); 1663 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1664 1665 PetscCall(VecGetLocalSize(coordinates, &N)); 1666 PetscCall(VecGetArrayRead(coordinates, &coords)); 1667 for (c = 0; c < N; c += dim) { 1668 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1669 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1670 } 1671 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1672 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1673 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1674 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1675 PetscCall(PetscDrawClear(draw)); 1676 1677 for (c = cStart; c < cEnd; ++c) { 1678 PetscScalar *coords = NULL; 1679 PetscInt numCoords; 1680 1681 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1682 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1683 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1684 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1685 } 1686 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1687 PetscCall(PetscDrawFlush(draw)); 1688 PetscCall(PetscDrawPause(draw)); 1689 PetscCall(PetscDrawSave(draw)); 1690 PetscFunctionReturn(0); 1691 } 1692 1693 #if defined(PETSC_HAVE_EXODUSII) 1694 #include <exodusII.h> 1695 #include <petscviewerexodusii.h> 1696 #endif 1697 1698 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1699 { 1700 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1701 char name[PETSC_MAX_PATH_LEN]; 1702 1703 PetscFunctionBegin; 1704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1705 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1706 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1707 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1708 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1709 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1710 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1711 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1712 if (iascii) { 1713 PetscViewerFormat format; 1714 PetscCall(PetscViewerGetFormat(viewer, &format)); 1715 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1716 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1717 } else if (ishdf5) { 1718 #if defined(PETSC_HAVE_HDF5) 1719 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1720 #else 1721 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1722 #endif 1723 } else if (isvtk) { 1724 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1725 } else if (isdraw) { 1726 PetscCall(DMPlexView_Draw(dm, viewer)); 1727 } else if (isglvis) { 1728 PetscCall(DMPlexView_GLVis(dm, viewer)); 1729 #if defined(PETSC_HAVE_EXODUSII) 1730 } else if (isexodus) { 1731 /* 1732 exodusII requires that all sets be part of exactly one cell set. 1733 If the dm does not have a "Cell Sets" label defined, we create one 1734 with ID 1, containig all cells. 1735 Note that if the Cell Sets label is defined but does not cover all cells, 1736 we may still have a problem. This should probably be checked here or in the viewer; 1737 */ 1738 PetscInt numCS; 1739 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1740 if (!numCS) { 1741 PetscInt cStart, cEnd, c; 1742 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1743 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1744 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1745 } 1746 PetscCall(DMView_PlexExodusII(dm, viewer)); 1747 #endif 1748 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1749 1750 /* Optionally view the partition */ 1751 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1752 if (flg) { 1753 Vec ranks; 1754 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1755 PetscCall(VecView(ranks, viewer)); 1756 PetscCall(VecDestroy(&ranks)); 1757 } 1758 /* Optionally view a label */ 1759 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1760 if (flg) { 1761 DMLabel label; 1762 Vec val; 1763 1764 PetscCall(DMGetLabel(dm, name, &label)); 1765 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1766 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1767 PetscCall(VecView(val, viewer)); 1768 PetscCall(VecDestroy(&val)); 1769 } 1770 PetscFunctionReturn(0); 1771 } 1772 1773 /*@ 1774 DMPlexTopologyView - Saves a DMPlex topology into a file 1775 1776 Collective on DM 1777 1778 Input Parameters: 1779 + dm - The DM whose topology is to be saved 1780 - viewer - The PetscViewer for saving 1781 1782 Level: advanced 1783 1784 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1785 @*/ 1786 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1787 { 1788 PetscBool ishdf5; 1789 1790 PetscFunctionBegin; 1791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1792 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1793 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1794 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1795 if (ishdf5) { 1796 #if defined(PETSC_HAVE_HDF5) 1797 PetscViewerFormat format; 1798 PetscCall(PetscViewerGetFormat(viewer, &format)); 1799 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1800 IS globalPointNumbering; 1801 1802 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1803 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1804 PetscCall(ISDestroy(&globalPointNumbering)); 1805 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1806 #else 1807 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1808 #endif 1809 } 1810 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1811 PetscFunctionReturn(0); 1812 } 1813 1814 /*@ 1815 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1816 1817 Collective on DM 1818 1819 Input Parameters: 1820 + dm - The DM whose coordinates are to be saved 1821 - viewer - The PetscViewer for saving 1822 1823 Level: advanced 1824 1825 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1826 @*/ 1827 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1828 { 1829 PetscBool ishdf5; 1830 1831 PetscFunctionBegin; 1832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1833 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1834 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1835 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1836 if (ishdf5) { 1837 #if defined(PETSC_HAVE_HDF5) 1838 PetscViewerFormat format; 1839 PetscCall(PetscViewerGetFormat(viewer, &format)); 1840 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1841 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1842 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1843 #else 1844 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1845 #endif 1846 } 1847 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1848 PetscFunctionReturn(0); 1849 } 1850 1851 /*@ 1852 DMPlexLabelsView - Saves DMPlex labels into a file 1853 1854 Collective on DM 1855 1856 Input Parameters: 1857 + dm - The DM whose labels are to be saved 1858 - viewer - The PetscViewer for saving 1859 1860 Level: advanced 1861 1862 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1863 @*/ 1864 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1865 { 1866 PetscBool ishdf5; 1867 1868 PetscFunctionBegin; 1869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1870 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1871 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1872 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1873 if (ishdf5) { 1874 #if defined(PETSC_HAVE_HDF5) 1875 IS globalPointNumbering; 1876 PetscViewerFormat format; 1877 1878 PetscCall(PetscViewerGetFormat(viewer, &format)); 1879 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1880 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1881 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1882 PetscCall(ISDestroy(&globalPointNumbering)); 1883 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1884 #else 1885 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1886 #endif 1887 } 1888 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1889 PetscFunctionReturn(0); 1890 } 1891 1892 /*@ 1893 DMPlexSectionView - Saves a section associated with a DMPlex 1894 1895 Collective on DM 1896 1897 Input Parameters: 1898 + dm - The DM that contains the topology on which the section to be saved is defined 1899 . viewer - The PetscViewer for saving 1900 - sectiondm - The DM that contains the section to be saved 1901 1902 Level: advanced 1903 1904 Notes: 1905 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. 1906 1907 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. 1908 1909 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1910 @*/ 1911 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1912 { 1913 PetscBool ishdf5; 1914 1915 PetscFunctionBegin; 1916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1917 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1918 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1919 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1920 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1921 if (ishdf5) { 1922 #if defined(PETSC_HAVE_HDF5) 1923 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1924 #else 1925 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1926 #endif 1927 } 1928 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1929 PetscFunctionReturn(0); 1930 } 1931 1932 /*@ 1933 DMPlexGlobalVectorView - Saves a global vector 1934 1935 Collective on DM 1936 1937 Input Parameters: 1938 + dm - The DM that represents the topology 1939 . viewer - The PetscViewer to save data with 1940 . sectiondm - The DM that contains the global section on which vec is defined 1941 - vec - The global vector to be saved 1942 1943 Level: advanced 1944 1945 Notes: 1946 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. 1947 1948 Typical calling sequence 1949 $ DMCreate(PETSC_COMM_WORLD, &dm); 1950 $ DMSetType(dm, DMPLEX); 1951 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1952 $ DMClone(dm, §iondm); 1953 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1954 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1955 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1956 $ PetscSectionSetChart(section, pStart, pEnd); 1957 $ PetscSectionSetUp(section); 1958 $ DMSetLocalSection(sectiondm, section); 1959 $ PetscSectionDestroy(§ion); 1960 $ DMGetGlobalVector(sectiondm, &vec); 1961 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1962 $ DMPlexTopologyView(dm, viewer); 1963 $ DMPlexSectionView(dm, viewer, sectiondm); 1964 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1965 $ DMRestoreGlobalVector(sectiondm, &vec); 1966 $ DMDestroy(§iondm); 1967 $ DMDestroy(&dm); 1968 1969 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1970 @*/ 1971 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1972 { 1973 PetscBool ishdf5; 1974 1975 PetscFunctionBegin; 1976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1977 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1978 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1979 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1980 /* Check consistency */ 1981 { 1982 PetscSection section; 1983 PetscBool includesConstraints; 1984 PetscInt m, m1; 1985 1986 PetscCall(VecGetLocalSize(vec, &m1)); 1987 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1988 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1989 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1990 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1991 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1992 } 1993 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1994 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1995 if (ishdf5) { 1996 #if defined(PETSC_HAVE_HDF5) 1997 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1998 #else 1999 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2000 #endif 2001 } 2002 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2003 PetscFunctionReturn(0); 2004 } 2005 2006 /*@ 2007 DMPlexLocalVectorView - Saves a local vector 2008 2009 Collective on DM 2010 2011 Input Parameters: 2012 + dm - The DM that represents the topology 2013 . viewer - The PetscViewer to save data with 2014 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2015 - vec - The local vector to be saved 2016 2017 Level: advanced 2018 2019 Notes: 2020 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. 2021 2022 Typical calling sequence 2023 $ DMCreate(PETSC_COMM_WORLD, &dm); 2024 $ DMSetType(dm, DMPLEX); 2025 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2026 $ DMClone(dm, §iondm); 2027 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2028 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2029 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2030 $ PetscSectionSetChart(section, pStart, pEnd); 2031 $ PetscSectionSetUp(section); 2032 $ DMSetLocalSection(sectiondm, section); 2033 $ DMGetLocalVector(sectiondm, &vec); 2034 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2035 $ DMPlexTopologyView(dm, viewer); 2036 $ DMPlexSectionView(dm, viewer, sectiondm); 2037 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2038 $ DMRestoreLocalVector(sectiondm, &vec); 2039 $ DMDestroy(§iondm); 2040 $ DMDestroy(&dm); 2041 2042 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2043 @*/ 2044 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2045 { 2046 PetscBool ishdf5; 2047 2048 PetscFunctionBegin; 2049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2050 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2051 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2052 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2053 /* Check consistency */ 2054 { 2055 PetscSection section; 2056 PetscBool includesConstraints; 2057 PetscInt m, m1; 2058 2059 PetscCall(VecGetLocalSize(vec, &m1)); 2060 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2061 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2062 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2063 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2064 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2065 } 2066 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2067 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2068 if (ishdf5) { 2069 #if defined(PETSC_HAVE_HDF5) 2070 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2071 #else 2072 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2073 #endif 2074 } 2075 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2076 PetscFunctionReturn(0); 2077 } 2078 2079 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2080 { 2081 PetscBool ishdf5; 2082 2083 PetscFunctionBegin; 2084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2085 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2086 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2087 if (ishdf5) { 2088 #if defined(PETSC_HAVE_HDF5) 2089 PetscViewerFormat format; 2090 PetscCall(PetscViewerGetFormat(viewer, &format)); 2091 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2092 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2093 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2094 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2096 PetscFunctionReturn(0); 2097 #else 2098 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2099 #endif 2100 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2101 } 2102 2103 /*@ 2104 DMPlexTopologyLoad - Loads a topology into a DMPlex 2105 2106 Collective on DM 2107 2108 Input Parameters: 2109 + dm - The DM into which the topology is loaded 2110 - viewer - The PetscViewer for the saved topology 2111 2112 Output Parameters: 2113 . 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 2114 2115 Level: advanced 2116 2117 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2118 @*/ 2119 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2120 { 2121 PetscBool ishdf5; 2122 2123 PetscFunctionBegin; 2124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2125 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2126 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2127 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2128 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2129 if (ishdf5) { 2130 #if defined(PETSC_HAVE_HDF5) 2131 PetscViewerFormat format; 2132 PetscCall(PetscViewerGetFormat(viewer, &format)); 2133 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2134 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2135 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2141 PetscFunctionReturn(0); 2142 } 2143 2144 /*@ 2145 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2146 2147 Collective on DM 2148 2149 Input Parameters: 2150 + dm - The DM into which the coordinates are loaded 2151 . viewer - The PetscViewer for the saved coordinates 2152 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2153 2154 Level: advanced 2155 2156 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2157 @*/ 2158 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2159 { 2160 PetscBool ishdf5; 2161 2162 PetscFunctionBegin; 2163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2164 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2165 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2166 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2167 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2168 if (ishdf5) { 2169 #if defined(PETSC_HAVE_HDF5) 2170 PetscViewerFormat format; 2171 PetscCall(PetscViewerGetFormat(viewer, &format)); 2172 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2173 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2174 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2175 #else 2176 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2177 #endif 2178 } 2179 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2180 PetscFunctionReturn(0); 2181 } 2182 2183 /*@ 2184 DMPlexLabelsLoad - Loads labels into a DMPlex 2185 2186 Collective on DM 2187 2188 Input Parameters: 2189 + dm - The DM into which the labels are loaded 2190 . viewer - The PetscViewer for the saved labels 2191 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2192 2193 Level: advanced 2194 2195 Notes: 2196 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2197 2198 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2199 @*/ 2200 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2201 { 2202 PetscBool ishdf5; 2203 2204 PetscFunctionBegin; 2205 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2206 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2207 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2208 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2209 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2210 if (ishdf5) { 2211 #if defined(PETSC_HAVE_HDF5) 2212 PetscViewerFormat format; 2213 2214 PetscCall(PetscViewerGetFormat(viewer, &format)); 2215 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2216 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2217 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2218 #else 2219 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2220 #endif 2221 } 2222 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2223 PetscFunctionReturn(0); 2224 } 2225 2226 /*@ 2227 DMPlexSectionLoad - Loads section into a DMPlex 2228 2229 Collective on DM 2230 2231 Input Parameters: 2232 + dm - The DM that represents the topology 2233 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2234 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2235 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2236 2237 Output Parameters 2238 + 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) 2239 - 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) 2240 2241 Level: advanced 2242 2243 Notes: 2244 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. 2245 2246 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. 2247 2248 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. 2249 2250 Example using 2 processes: 2251 $ NX (number of points on dm): 4 2252 $ sectionA : the on-disk section 2253 $ vecA : a vector associated with sectionA 2254 $ sectionB : sectiondm's local section constructed in this function 2255 $ vecB (local) : a vector associated with sectiondm's local section 2256 $ vecB (global) : a vector associated with sectiondm's global section 2257 $ 2258 $ rank 0 rank 1 2259 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2260 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2261 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2262 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2263 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2264 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2265 $ sectionB->atlasDof : 1 0 1 | 1 3 2266 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2267 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2268 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2269 $ 2270 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2271 2272 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2273 @*/ 2274 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2275 { 2276 PetscBool ishdf5; 2277 2278 PetscFunctionBegin; 2279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2280 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2281 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2282 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2283 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2284 if (localDofSF) PetscValidPointer(localDofSF, 6); 2285 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2286 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2287 if (ishdf5) { 2288 #if defined(PETSC_HAVE_HDF5) 2289 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2290 #else 2291 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2292 #endif 2293 } 2294 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2295 PetscFunctionReturn(0); 2296 } 2297 2298 /*@ 2299 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2300 2301 Collective on DM 2302 2303 Input Parameters: 2304 + dm - The DM that represents the topology 2305 . viewer - The PetscViewer that represents the on-disk vector data 2306 . sectiondm - The DM that contains the global section on which vec is defined 2307 . sf - The SF that migrates the on-disk vector data into vec 2308 - vec - The global vector to set values of 2309 2310 Level: advanced 2311 2312 Notes: 2313 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. 2314 2315 Typical calling sequence 2316 $ DMCreate(PETSC_COMM_WORLD, &dm); 2317 $ DMSetType(dm, DMPLEX); 2318 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2319 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2320 $ DMClone(dm, §iondm); 2321 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2322 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2323 $ DMGetGlobalVector(sectiondm, &vec); 2324 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2325 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2326 $ DMRestoreGlobalVector(sectiondm, &vec); 2327 $ PetscSFDestroy(&gsf); 2328 $ PetscSFDestroy(&sfX); 2329 $ DMDestroy(§iondm); 2330 $ DMDestroy(&dm); 2331 2332 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2333 @*/ 2334 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2335 { 2336 PetscBool ishdf5; 2337 2338 PetscFunctionBegin; 2339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2341 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2342 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2343 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2344 /* Check consistency */ 2345 { 2346 PetscSection section; 2347 PetscBool includesConstraints; 2348 PetscInt m, m1; 2349 2350 PetscCall(VecGetLocalSize(vec, &m1)); 2351 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2352 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2353 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2354 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2355 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2356 } 2357 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2358 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2359 if (ishdf5) { 2360 #if defined(PETSC_HAVE_HDF5) 2361 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2362 #else 2363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2364 #endif 2365 } 2366 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2367 PetscFunctionReturn(0); 2368 } 2369 2370 /*@ 2371 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2372 2373 Collective on DM 2374 2375 Input Parameters: 2376 + dm - The DM that represents the topology 2377 . viewer - The PetscViewer that represents the on-disk vector data 2378 . sectiondm - The DM that contains the local section on which vec is defined 2379 . sf - The SF that migrates the on-disk vector data into vec 2380 - vec - The local vector to set values of 2381 2382 Level: advanced 2383 2384 Notes: 2385 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. 2386 2387 Typical calling sequence 2388 $ DMCreate(PETSC_COMM_WORLD, &dm); 2389 $ DMSetType(dm, DMPLEX); 2390 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2391 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2392 $ DMClone(dm, §iondm); 2393 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2394 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2395 $ DMGetLocalVector(sectiondm, &vec); 2396 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2397 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2398 $ DMRestoreLocalVector(sectiondm, &vec); 2399 $ PetscSFDestroy(&lsf); 2400 $ PetscSFDestroy(&sfX); 2401 $ DMDestroy(§iondm); 2402 $ DMDestroy(&dm); 2403 2404 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2405 @*/ 2406 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2407 { 2408 PetscBool ishdf5; 2409 2410 PetscFunctionBegin; 2411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2412 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2413 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2414 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2415 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2416 /* Check consistency */ 2417 { 2418 PetscSection section; 2419 PetscBool includesConstraints; 2420 PetscInt m, m1; 2421 2422 PetscCall(VecGetLocalSize(vec, &m1)); 2423 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2424 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2425 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2426 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2427 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2428 } 2429 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2430 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2431 if (ishdf5) { 2432 #if defined(PETSC_HAVE_HDF5) 2433 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2434 #else 2435 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2436 #endif 2437 } 2438 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2439 PetscFunctionReturn(0); 2440 } 2441 2442 PetscErrorCode DMDestroy_Plex(DM dm) 2443 { 2444 DM_Plex *mesh = (DM_Plex*) dm->data; 2445 2446 PetscFunctionBegin; 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2460 if (--mesh->refct > 0) PetscFunctionReturn(0); 2461 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2462 PetscCall(PetscFree(mesh->cones)); 2463 PetscCall(PetscFree(mesh->coneOrientations)); 2464 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2465 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2466 PetscCall(PetscFree(mesh->supports)); 2467 PetscCall(PetscFree(mesh->facesTmp)); 2468 PetscCall(PetscFree(mesh->tetgenOpts)); 2469 PetscCall(PetscFree(mesh->triangleOpts)); 2470 PetscCall(PetscFree(mesh->transformType)); 2471 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2472 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2473 PetscCall(ISDestroy(&mesh->subpointIS)); 2474 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2475 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2476 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2477 PetscCall(ISDestroy(&mesh->anchorIS)); 2478 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2479 PetscCall(PetscFree(mesh->parents)); 2480 PetscCall(PetscFree(mesh->childIDs)); 2481 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2482 PetscCall(PetscFree(mesh->children)); 2483 PetscCall(DMDestroy(&mesh->referenceTree)); 2484 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2485 PetscCall(PetscFree(mesh->neighbors)); 2486 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2487 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2488 PetscCall(PetscFree(mesh)); 2489 PetscFunctionReturn(0); 2490 } 2491 2492 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2493 { 2494 PetscSection sectionGlobal; 2495 PetscInt bs = -1, mbs; 2496 PetscInt localSize, localStart = 0; 2497 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2498 MatType mtype; 2499 ISLocalToGlobalMapping ltog; 2500 2501 PetscFunctionBegin; 2502 PetscCall(MatInitializePackage()); 2503 mtype = dm->mattype; 2504 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2505 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2506 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2507 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2508 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2509 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2510 PetscCall(MatSetType(*J, mtype)); 2511 PetscCall(MatSetFromOptions(*J)); 2512 PetscCall(MatGetBlockSize(*J, &mbs)); 2513 if (mbs > 1) bs = mbs; 2514 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2515 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2516 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2522 if (!isShell) { 2523 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2524 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2525 PetscInt pStart, pEnd, p, dof, cdof; 2526 2527 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2528 2529 PetscCall(PetscCalloc1(localSize, &pblocks)); 2530 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2531 for (p = pStart; p < pEnd; ++p) { 2532 PetscInt bdof, offset; 2533 2534 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2535 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2536 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2537 for (PetscInt i=0; i < dof - cdof; i++) 2538 pblocks[offset - localStart + i] = dof - cdof; 2539 dof = dof < 0 ? -(dof+1) : dof; 2540 bdof = cdof && (dof-cdof) ? 1 : dof; 2541 if (dof) { 2542 if (bs < 0) {bs = bdof;} 2543 else if (bs != bdof) {bs = 1;} 2544 } 2545 } 2546 /* Must have same blocksize on all procs (some might have no points) */ 2547 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2548 bsLocal[1] = bs; 2549 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2550 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2551 else bs = bsMinMax[0]; 2552 bs = PetscMax(1,bs); 2553 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2554 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2555 PetscCall(MatSetBlockSize(*J, bs)); 2556 PetscCall(MatSetUp(*J)); 2557 } else { 2558 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2559 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2560 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2561 } 2562 { // Consolidate blocks 2563 PetscInt nblocks = 0; 2564 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2565 if (pblocks[i] == 0) continue; 2566 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2567 for (PetscInt j=1; j<pblocks[i]; j++) { 2568 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]); 2569 } 2570 } 2571 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2572 } 2573 PetscCall(PetscFree(pblocks)); 2574 } 2575 PetscCall(MatSetDM(*J, dm)); 2576 PetscFunctionReturn(0); 2577 } 2578 2579 /*@ 2580 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2581 2582 Not collective 2583 2584 Input Parameter: 2585 . mesh - The DMPlex 2586 2587 Output Parameters: 2588 . subsection - The subdomain section 2589 2590 Level: developer 2591 2592 .seealso: 2593 @*/ 2594 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2595 { 2596 DM_Plex *mesh = (DM_Plex*) dm->data; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 if (!mesh->subdomainSection) { 2601 PetscSection section; 2602 PetscSF sf; 2603 2604 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2605 PetscCall(DMGetLocalSection(dm,§ion)); 2606 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2607 PetscCall(PetscSFDestroy(&sf)); 2608 } 2609 *subsection = mesh->subdomainSection; 2610 PetscFunctionReturn(0); 2611 } 2612 2613 /*@ 2614 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2615 2616 Not collective 2617 2618 Input Parameter: 2619 . mesh - The DMPlex 2620 2621 Output Parameters: 2622 + pStart - The first mesh point 2623 - pEnd - The upper bound for mesh points 2624 2625 Level: beginner 2626 2627 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2628 @*/ 2629 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2630 { 2631 DM_Plex *mesh = (DM_Plex*) dm->data; 2632 2633 PetscFunctionBegin; 2634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2635 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2636 PetscFunctionReturn(0); 2637 } 2638 2639 /*@ 2640 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2641 2642 Not collective 2643 2644 Input Parameters: 2645 + mesh - The DMPlex 2646 . pStart - The first mesh point 2647 - pEnd - The upper bound for mesh points 2648 2649 Output Parameters: 2650 2651 Level: beginner 2652 2653 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2654 @*/ 2655 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2656 { 2657 DM_Plex *mesh = (DM_Plex*) dm->data; 2658 2659 PetscFunctionBegin; 2660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2661 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2662 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2663 PetscFunctionReturn(0); 2664 } 2665 2666 /*@ 2667 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2668 2669 Not collective 2670 2671 Input Parameters: 2672 + mesh - The DMPlex 2673 - p - The point, which must lie in the chart set with DMPlexSetChart() 2674 2675 Output Parameter: 2676 . size - The cone size for point p 2677 2678 Level: beginner 2679 2680 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2681 @*/ 2682 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2683 { 2684 DM_Plex *mesh = (DM_Plex*) dm->data; 2685 2686 PetscFunctionBegin; 2687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2688 PetscValidIntPointer(size, 3); 2689 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2690 PetscFunctionReturn(0); 2691 } 2692 2693 /*@ 2694 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2695 2696 Not collective 2697 2698 Input Parameters: 2699 + mesh - The DMPlex 2700 . p - The point, which must lie in the chart set with DMPlexSetChart() 2701 - size - The cone size for point p 2702 2703 Output Parameter: 2704 2705 Note: 2706 This should be called after DMPlexSetChart(). 2707 2708 Level: beginner 2709 2710 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2711 @*/ 2712 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2713 { 2714 DM_Plex *mesh = (DM_Plex*) dm->data; 2715 2716 PetscFunctionBegin; 2717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2718 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2719 PetscFunctionReturn(0); 2720 } 2721 2722 /*@ 2723 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2724 2725 Not collective 2726 2727 Input Parameters: 2728 + mesh - The DMPlex 2729 . p - The point, which must lie in the chart set with DMPlexSetChart() 2730 - size - The additional cone size for point p 2731 2732 Output Parameter: 2733 2734 Note: 2735 This should be called after DMPlexSetChart(). 2736 2737 Level: beginner 2738 2739 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2740 @*/ 2741 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2742 { 2743 DM_Plex *mesh = (DM_Plex*) dm->data; 2744 PetscFunctionBegin; 2745 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2746 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2747 PetscFunctionReturn(0); 2748 } 2749 2750 /*@C 2751 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2752 2753 Not collective 2754 2755 Input Parameters: 2756 + dm - The DMPlex 2757 - p - The point, which must lie in the chart set with DMPlexSetChart() 2758 2759 Output Parameter: 2760 . cone - An array of points which are on the in-edges for point p 2761 2762 Level: beginner 2763 2764 Fortran Notes: 2765 Since it returns an array, this routine is only available in Fortran 90, and you must 2766 include petsc.h90 in your code. 2767 You must also call DMPlexRestoreCone() after you finish using the returned array. 2768 DMPlexRestoreCone() is not needed/available in C. 2769 2770 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2771 @*/ 2772 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2773 { 2774 DM_Plex *mesh = (DM_Plex*) dm->data; 2775 PetscInt off; 2776 2777 PetscFunctionBegin; 2778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2779 PetscValidPointer(cone, 3); 2780 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2781 *cone = &mesh->cones[off]; 2782 PetscFunctionReturn(0); 2783 } 2784 2785 /*@C 2786 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2787 2788 Not collective 2789 2790 Input Parameters: 2791 + dm - The DMPlex 2792 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2793 2794 Output Parameters: 2795 + pConesSection - PetscSection describing the layout of pCones 2796 - pCones - An array of points which are on the in-edges for the point set p 2797 2798 Level: intermediate 2799 2800 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2801 @*/ 2802 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2803 { 2804 PetscSection cs, newcs; 2805 PetscInt *cones; 2806 PetscInt *newarr=NULL; 2807 PetscInt n; 2808 2809 PetscFunctionBegin; 2810 PetscCall(DMPlexGetCones(dm, &cones)); 2811 PetscCall(DMPlexGetConeSection(dm, &cs)); 2812 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2813 if (pConesSection) *pConesSection = newcs; 2814 if (pCones) { 2815 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2816 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2817 } 2818 PetscFunctionReturn(0); 2819 } 2820 2821 /*@ 2822 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2823 2824 Not collective 2825 2826 Input Parameters: 2827 + dm - The DMPlex 2828 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2829 2830 Output Parameter: 2831 . expandedPoints - An array of vertices recursively expanded from input points 2832 2833 Level: advanced 2834 2835 Notes: 2836 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2837 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2838 2839 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2840 @*/ 2841 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2842 { 2843 IS *expandedPointsAll; 2844 PetscInt depth; 2845 2846 PetscFunctionBegin; 2847 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2848 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2849 PetscValidPointer(expandedPoints, 3); 2850 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2851 *expandedPoints = expandedPointsAll[0]; 2852 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2853 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2854 PetscFunctionReturn(0); 2855 } 2856 2857 /*@ 2858 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). 2859 2860 Not collective 2861 2862 Input Parameters: 2863 + dm - The DMPlex 2864 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2865 2866 Output Parameters: 2867 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2868 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2869 - sections - (optional) An array of sections which describe mappings from points to their cone points 2870 2871 Level: advanced 2872 2873 Notes: 2874 Like DMPlexGetConeTuple() but recursive. 2875 2876 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. 2877 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2878 2879 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: 2880 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2881 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2882 2883 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2884 @*/ 2885 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2886 { 2887 const PetscInt *arr0=NULL, *cone=NULL; 2888 PetscInt *arr=NULL, *newarr=NULL; 2889 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2890 IS *expandedPoints_; 2891 PetscSection *sections_; 2892 2893 PetscFunctionBegin; 2894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2895 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2896 if (depth) PetscValidIntPointer(depth, 3); 2897 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2898 if (sections) PetscValidPointer(sections, 5); 2899 PetscCall(ISGetLocalSize(points, &n)); 2900 PetscCall(ISGetIndices(points, &arr0)); 2901 PetscCall(DMPlexGetDepth(dm, &depth_)); 2902 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2903 PetscCall(PetscCalloc1(depth_, §ions_)); 2904 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2905 for (d=depth_-1; d>=0; d--) { 2906 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2907 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2908 for (i=0; i<n; i++) { 2909 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2910 if (arr[i] >= start && arr[i] < end) { 2911 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2912 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2913 } else { 2914 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2915 } 2916 } 2917 PetscCall(PetscSectionSetUp(sections_[d])); 2918 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2919 PetscCall(PetscMalloc1(newn, &newarr)); 2920 for (i=0; i<n; i++) { 2921 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2922 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2923 if (cn > 1) { 2924 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2925 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2926 } else { 2927 newarr[co] = arr[i]; 2928 } 2929 } 2930 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2931 arr = newarr; 2932 n = newn; 2933 } 2934 PetscCall(ISRestoreIndices(points, &arr0)); 2935 *depth = depth_; 2936 if (expandedPoints) *expandedPoints = expandedPoints_; 2937 else { 2938 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2939 PetscCall(PetscFree(expandedPoints_)); 2940 } 2941 if (sections) *sections = sections_; 2942 else { 2943 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2944 PetscCall(PetscFree(sections_)); 2945 } 2946 PetscFunctionReturn(0); 2947 } 2948 2949 /*@ 2950 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2951 2952 Not collective 2953 2954 Input Parameters: 2955 + dm - The DMPlex 2956 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2957 2958 Output Parameters: 2959 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2960 . expandedPoints - (optional) An array of recursively expanded cones 2961 - sections - (optional) An array of sections which describe mappings from points to their cone points 2962 2963 Level: advanced 2964 2965 Notes: 2966 See DMPlexGetConeRecursive() for details. 2967 2968 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2969 @*/ 2970 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2971 { 2972 PetscInt d, depth_; 2973 2974 PetscFunctionBegin; 2975 PetscCall(DMPlexGetDepth(dm, &depth_)); 2976 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2977 if (depth) *depth = 0; 2978 if (expandedPoints) { 2979 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2980 PetscCall(PetscFree(*expandedPoints)); 2981 } 2982 if (sections) { 2983 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2984 PetscCall(PetscFree(*sections)); 2985 } 2986 PetscFunctionReturn(0); 2987 } 2988 2989 /*@ 2990 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 2991 2992 Not collective 2993 2994 Input Parameters: 2995 + mesh - The DMPlex 2996 . p - The point, which must lie in the chart set with DMPlexSetChart() 2997 - cone - An array of points which are on the in-edges for point p 2998 2999 Output Parameter: 3000 3001 Note: 3002 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3003 3004 Level: beginner 3005 3006 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3007 @*/ 3008 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3009 { 3010 DM_Plex *mesh = (DM_Plex*) dm->data; 3011 PetscInt pStart, pEnd; 3012 PetscInt dof, off, c; 3013 3014 PetscFunctionBegin; 3015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3016 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3017 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3018 if (dof) PetscValidIntPointer(cone, 3); 3019 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3020 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); 3021 for (c = 0; c < dof; ++c) { 3022 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); 3023 mesh->cones[off+c] = cone[c]; 3024 } 3025 PetscFunctionReturn(0); 3026 } 3027 3028 /*@C 3029 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3030 3031 Not collective 3032 3033 Input Parameters: 3034 + mesh - The DMPlex 3035 - p - The point, which must lie in the chart set with DMPlexSetChart() 3036 3037 Output Parameter: 3038 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3039 integer giving the prescription for cone traversal. 3040 3041 Level: beginner 3042 3043 Notes: 3044 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3045 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3046 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3047 with the identity. 3048 3049 Fortran Notes: 3050 Since it returns an array, this routine is only available in Fortran 90, and you must 3051 include petsc.h90 in your code. 3052 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3053 DMPlexRestoreConeOrientation() is not needed/available in C. 3054 3055 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3056 @*/ 3057 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3058 { 3059 DM_Plex *mesh = (DM_Plex*) dm->data; 3060 PetscInt off; 3061 3062 PetscFunctionBegin; 3063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3064 if (PetscDefined(USE_DEBUG)) { 3065 PetscInt dof; 3066 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3067 if (dof) PetscValidPointer(coneOrientation, 3); 3068 } 3069 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3070 3071 *coneOrientation = &mesh->coneOrientations[off]; 3072 PetscFunctionReturn(0); 3073 } 3074 3075 /*@ 3076 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3077 3078 Not collective 3079 3080 Input Parameters: 3081 + mesh - The DMPlex 3082 . p - The point, which must lie in the chart set with DMPlexSetChart() 3083 - coneOrientation - An array of orientations 3084 Output Parameter: 3085 3086 Notes: 3087 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3088 3089 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3090 3091 Level: beginner 3092 3093 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3094 @*/ 3095 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3096 { 3097 DM_Plex *mesh = (DM_Plex*) dm->data; 3098 PetscInt pStart, pEnd; 3099 PetscInt dof, off, c; 3100 3101 PetscFunctionBegin; 3102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3103 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3104 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3105 if (dof) PetscValidIntPointer(coneOrientation, 3); 3106 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3107 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); 3108 for (c = 0; c < dof; ++c) { 3109 PetscInt cdof, o = coneOrientation[c]; 3110 3111 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3112 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); 3113 mesh->coneOrientations[off+c] = o; 3114 } 3115 PetscFunctionReturn(0); 3116 } 3117 3118 /*@ 3119 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3120 3121 Not collective 3122 3123 Input Parameters: 3124 + mesh - The DMPlex 3125 . p - The point, which must lie in the chart set with DMPlexSetChart() 3126 . conePos - The local index in the cone where the point should be put 3127 - conePoint - The mesh point to insert 3128 3129 Level: beginner 3130 3131 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3132 @*/ 3133 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3134 { 3135 DM_Plex *mesh = (DM_Plex*) dm->data; 3136 PetscInt pStart, pEnd; 3137 PetscInt dof, off; 3138 3139 PetscFunctionBegin; 3140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3141 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3142 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); 3143 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); 3144 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3145 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3146 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); 3147 mesh->cones[off+conePos] = conePoint; 3148 PetscFunctionReturn(0); 3149 } 3150 3151 /*@ 3152 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3153 3154 Not collective 3155 3156 Input Parameters: 3157 + mesh - The DMPlex 3158 . p - The point, which must lie in the chart set with DMPlexSetChart() 3159 . conePos - The local index in the cone where the point should be put 3160 - coneOrientation - The point orientation to insert 3161 3162 Level: beginner 3163 3164 Notes: 3165 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3166 3167 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3168 @*/ 3169 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3170 { 3171 DM_Plex *mesh = (DM_Plex*) dm->data; 3172 PetscInt pStart, pEnd; 3173 PetscInt dof, off; 3174 3175 PetscFunctionBegin; 3176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3177 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3178 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); 3179 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3180 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3181 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); 3182 mesh->coneOrientations[off+conePos] = coneOrientation; 3183 PetscFunctionReturn(0); 3184 } 3185 3186 /*@ 3187 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3188 3189 Not collective 3190 3191 Input Parameters: 3192 + mesh - The DMPlex 3193 - p - The point, which must lie in the chart set with DMPlexSetChart() 3194 3195 Output Parameter: 3196 . size - The support size for point p 3197 3198 Level: beginner 3199 3200 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3201 @*/ 3202 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3203 { 3204 DM_Plex *mesh = (DM_Plex*) dm->data; 3205 3206 PetscFunctionBegin; 3207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3208 PetscValidIntPointer(size, 3); 3209 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3210 PetscFunctionReturn(0); 3211 } 3212 3213 /*@ 3214 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3215 3216 Not collective 3217 3218 Input Parameters: 3219 + mesh - The DMPlex 3220 . p - The point, which must lie in the chart set with DMPlexSetChart() 3221 - size - The support size for point p 3222 3223 Output Parameter: 3224 3225 Note: 3226 This should be called after DMPlexSetChart(). 3227 3228 Level: beginner 3229 3230 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3231 @*/ 3232 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3233 { 3234 DM_Plex *mesh = (DM_Plex*) dm->data; 3235 3236 PetscFunctionBegin; 3237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3238 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3239 PetscFunctionReturn(0); 3240 } 3241 3242 /*@C 3243 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3244 3245 Not collective 3246 3247 Input Parameters: 3248 + mesh - The DMPlex 3249 - p - The point, which must lie in the chart set with DMPlexSetChart() 3250 3251 Output Parameter: 3252 . support - An array of points which are on the out-edges for point p 3253 3254 Level: beginner 3255 3256 Fortran Notes: 3257 Since it returns an array, this routine is only available in Fortran 90, and you must 3258 include petsc.h90 in your code. 3259 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3260 DMPlexRestoreSupport() is not needed/available in C. 3261 3262 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3263 @*/ 3264 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3265 { 3266 DM_Plex *mesh = (DM_Plex*) dm->data; 3267 PetscInt off; 3268 3269 PetscFunctionBegin; 3270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3271 PetscValidPointer(support, 3); 3272 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3273 *support = &mesh->supports[off]; 3274 PetscFunctionReturn(0); 3275 } 3276 3277 /*@ 3278 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3279 3280 Not collective 3281 3282 Input Parameters: 3283 + mesh - The DMPlex 3284 . p - The point, which must lie in the chart set with DMPlexSetChart() 3285 - support - An array of points which are on the out-edges for point p 3286 3287 Output Parameter: 3288 3289 Note: 3290 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3291 3292 Level: beginner 3293 3294 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3295 @*/ 3296 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3297 { 3298 DM_Plex *mesh = (DM_Plex*) dm->data; 3299 PetscInt pStart, pEnd; 3300 PetscInt dof, off, c; 3301 3302 PetscFunctionBegin; 3303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3304 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3305 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3306 if (dof) PetscValidIntPointer(support, 3); 3307 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3308 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); 3309 for (c = 0; c < dof; ++c) { 3310 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); 3311 mesh->supports[off+c] = support[c]; 3312 } 3313 PetscFunctionReturn(0); 3314 } 3315 3316 /*@ 3317 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3318 3319 Not collective 3320 3321 Input Parameters: 3322 + mesh - The DMPlex 3323 . p - The point, which must lie in the chart set with DMPlexSetChart() 3324 . supportPos - The local index in the cone where the point should be put 3325 - supportPoint - The mesh point to insert 3326 3327 Level: beginner 3328 3329 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3330 @*/ 3331 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3332 { 3333 DM_Plex *mesh = (DM_Plex*) dm->data; 3334 PetscInt pStart, pEnd; 3335 PetscInt dof, off; 3336 3337 PetscFunctionBegin; 3338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3339 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3340 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3341 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3342 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); 3343 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); 3344 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); 3345 mesh->supports[off+supportPos] = supportPoint; 3346 PetscFunctionReturn(0); 3347 } 3348 3349 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3350 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3351 { 3352 switch (ct) { 3353 case DM_POLYTOPE_SEGMENT: 3354 if (o == -1) return -2; 3355 break; 3356 case DM_POLYTOPE_TRIANGLE: 3357 if (o == -3) return -1; 3358 if (o == -2) return -3; 3359 if (o == -1) return -2; 3360 break; 3361 case DM_POLYTOPE_QUADRILATERAL: 3362 if (o == -4) return -2; 3363 if (o == -3) return -1; 3364 if (o == -2) return -4; 3365 if (o == -1) return -3; 3366 break; 3367 default: return o; 3368 } 3369 return o; 3370 } 3371 3372 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3373 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3374 { 3375 switch (ct) { 3376 case DM_POLYTOPE_SEGMENT: 3377 if ((o == -2) || (o == 1)) return -1; 3378 if (o == -1) return 0; 3379 break; 3380 case DM_POLYTOPE_TRIANGLE: 3381 if (o == -3) return -2; 3382 if (o == -2) return -1; 3383 if (o == -1) return -3; 3384 break; 3385 case DM_POLYTOPE_QUADRILATERAL: 3386 if (o == -4) return -2; 3387 if (o == -3) return -1; 3388 if (o == -2) return -4; 3389 if (o == -1) return -3; 3390 break; 3391 default: return o; 3392 } 3393 return o; 3394 } 3395 3396 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3397 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3398 { 3399 PetscInt pStart, pEnd, p; 3400 3401 PetscFunctionBegin; 3402 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3403 for (p = pStart; p < pEnd; ++p) { 3404 const PetscInt *cone, *ornt; 3405 PetscInt coneSize, c; 3406 3407 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3408 PetscCall(DMPlexGetCone(dm, p, &cone)); 3409 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3410 for (c = 0; c < coneSize; ++c) { 3411 DMPolytopeType ct; 3412 const PetscInt o = ornt[c]; 3413 3414 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3415 switch (ct) { 3416 case DM_POLYTOPE_SEGMENT: 3417 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3418 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3419 break; 3420 case DM_POLYTOPE_TRIANGLE: 3421 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3422 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3423 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3424 break; 3425 case DM_POLYTOPE_QUADRILATERAL: 3426 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3427 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3428 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3429 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3430 break; 3431 default: break; 3432 } 3433 } 3434 } 3435 PetscFunctionReturn(0); 3436 } 3437 3438 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3439 { 3440 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3441 PetscInt *closure; 3442 const PetscInt *tmp = NULL, *tmpO = NULL; 3443 PetscInt off = 0, tmpSize, t; 3444 3445 PetscFunctionBeginHot; 3446 if (ornt) { 3447 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3448 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3449 } 3450 if (*points) { 3451 closure = *points; 3452 } else { 3453 PetscInt maxConeSize, maxSupportSize; 3454 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3455 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3456 } 3457 if (useCone) { 3458 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3459 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3460 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3461 } else { 3462 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3463 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3464 } 3465 if (ct == DM_POLYTOPE_UNKNOWN) { 3466 closure[off++] = p; 3467 closure[off++] = 0; 3468 for (t = 0; t < tmpSize; ++t) { 3469 closure[off++] = tmp[t]; 3470 closure[off++] = tmpO ? tmpO[t] : 0; 3471 } 3472 } else { 3473 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3474 3475 /* We assume that cells with a valid type have faces with a valid type */ 3476 closure[off++] = p; 3477 closure[off++] = ornt; 3478 for (t = 0; t < tmpSize; ++t) { 3479 DMPolytopeType ft; 3480 3481 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3482 closure[off++] = tmp[arr[t]]; 3483 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3484 } 3485 } 3486 if (numPoints) *numPoints = tmpSize+1; 3487 if (points) *points = closure; 3488 PetscFunctionReturn(0); 3489 } 3490 3491 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3492 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3493 { 3494 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3495 const PetscInt *cone, *ornt; 3496 PetscInt *pts, *closure = NULL; 3497 DMPolytopeType ft; 3498 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3499 PetscInt dim, coneSize, c, d, clSize, cl; 3500 3501 PetscFunctionBeginHot; 3502 PetscCall(DMGetDimension(dm, &dim)); 3503 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3504 PetscCall(DMPlexGetCone(dm, point, &cone)); 3505 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3506 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3507 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3508 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3509 maxSize = PetscMax(coneSeries, supportSeries); 3510 if (*points) {pts = *points;} 3511 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3512 c = 0; 3513 pts[c++] = point; 3514 pts[c++] = o; 3515 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3516 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3517 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3518 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3519 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3520 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3521 for (d = 2; d < coneSize; ++d) { 3522 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3523 pts[c++] = cone[arr[d*2+0]]; 3524 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3525 } 3526 if (dim >= 3) { 3527 for (d = 2; d < coneSize; ++d) { 3528 const PetscInt fpoint = cone[arr[d*2+0]]; 3529 const PetscInt *fcone, *fornt; 3530 PetscInt fconeSize, fc, i; 3531 3532 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3533 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3534 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3535 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3536 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3537 for (fc = 0; fc < fconeSize; ++fc) { 3538 const PetscInt cp = fcone[farr[fc*2+0]]; 3539 const PetscInt co = farr[fc*2+1]; 3540 3541 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3542 if (i == c) { 3543 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3544 pts[c++] = cp; 3545 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3546 } 3547 } 3548 } 3549 } 3550 *numPoints = c/2; 3551 *points = pts; 3552 PetscFunctionReturn(0); 3553 } 3554 3555 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3556 { 3557 DMPolytopeType ct; 3558 PetscInt *closure, *fifo; 3559 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3560 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3561 PetscInt depth, maxSize; 3562 3563 PetscFunctionBeginHot; 3564 PetscCall(DMPlexGetDepth(dm, &depth)); 3565 if (depth == 1) { 3566 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3567 PetscFunctionReturn(0); 3568 } 3569 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3570 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3571 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3572 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3573 PetscFunctionReturn(0); 3574 } 3575 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3576 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3577 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3578 maxSize = PetscMax(coneSeries, supportSeries); 3579 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3580 if (*points) {closure = *points;} 3581 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3582 closure[closureSize++] = p; 3583 closure[closureSize++] = ornt; 3584 fifo[fifoSize++] = p; 3585 fifo[fifoSize++] = ornt; 3586 fifo[fifoSize++] = ct; 3587 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3588 while (fifoSize - fifoStart) { 3589 const PetscInt q = fifo[fifoStart++]; 3590 const PetscInt o = fifo[fifoStart++]; 3591 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3592 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3593 const PetscInt *tmp, *tmpO; 3594 PetscInt tmpSize, t; 3595 3596 if (PetscDefined(USE_DEBUG)) { 3597 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3598 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); 3599 } 3600 if (useCone) { 3601 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3602 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3603 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3604 } else { 3605 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3606 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3607 tmpO = NULL; 3608 } 3609 for (t = 0; t < tmpSize; ++t) { 3610 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3611 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3612 const PetscInt cp = tmp[ip]; 3613 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3614 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3615 PetscInt c; 3616 3617 /* Check for duplicate */ 3618 for (c = 0; c < closureSize; c += 2) { 3619 if (closure[c] == cp) break; 3620 } 3621 if (c == closureSize) { 3622 closure[closureSize++] = cp; 3623 closure[closureSize++] = co; 3624 fifo[fifoSize++] = cp; 3625 fifo[fifoSize++] = co; 3626 fifo[fifoSize++] = ct; 3627 } 3628 } 3629 } 3630 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3631 if (numPoints) *numPoints = closureSize/2; 3632 if (points) *points = closure; 3633 PetscFunctionReturn(0); 3634 } 3635 3636 /*@C 3637 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3638 3639 Not collective 3640 3641 Input Parameters: 3642 + dm - The DMPlex 3643 . p - The mesh point 3644 - useCone - PETSC_TRUE for the closure, otherwise return the star 3645 3646 Input/Output Parameter: 3647 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3648 if NULL on input, internal storage will be returned, otherwise the provided array is used 3649 3650 Output Parameter: 3651 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3652 3653 Note: 3654 If using internal storage (points is NULL on input), each call overwrites the last output. 3655 3656 Fortran Notes: 3657 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3658 3659 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3660 3661 Level: beginner 3662 3663 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3664 @*/ 3665 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3666 { 3667 PetscFunctionBeginHot; 3668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3669 if (numPoints) PetscValidIntPointer(numPoints, 4); 3670 if (points) PetscValidPointer(points, 5); 3671 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3672 PetscFunctionReturn(0); 3673 } 3674 3675 /*@C 3676 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3677 3678 Not collective 3679 3680 Input Parameters: 3681 + dm - The DMPlex 3682 . p - The mesh point 3683 . useCone - PETSC_TRUE for the closure, otherwise return the star 3684 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3685 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3686 3687 Note: 3688 If not using internal storage (points is not NULL on input), this call is unnecessary 3689 3690 Fortran Notes: 3691 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3692 3693 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3694 3695 Level: beginner 3696 3697 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3698 @*/ 3699 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3700 { 3701 PetscFunctionBeginHot; 3702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3703 if (numPoints) *numPoints = 0; 3704 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3705 PetscFunctionReturn(0); 3706 } 3707 3708 /*@ 3709 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3710 3711 Not collective 3712 3713 Input Parameter: 3714 . mesh - The DMPlex 3715 3716 Output Parameters: 3717 + maxConeSize - The maximum number of in-edges 3718 - maxSupportSize - The maximum number of out-edges 3719 3720 Level: beginner 3721 3722 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3723 @*/ 3724 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3725 { 3726 DM_Plex *mesh = (DM_Plex*) dm->data; 3727 3728 PetscFunctionBegin; 3729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3730 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3731 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3732 PetscFunctionReturn(0); 3733 } 3734 3735 PetscErrorCode DMSetUp_Plex(DM dm) 3736 { 3737 DM_Plex *mesh = (DM_Plex*) dm->data; 3738 PetscInt size, maxSupportSize; 3739 3740 PetscFunctionBegin; 3741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3742 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3743 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3744 PetscCall(PetscMalloc1(size, &mesh->cones)); 3745 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3746 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3747 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3748 if (maxSupportSize) { 3749 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3750 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3751 PetscCall(PetscMalloc1(size, &mesh->supports)); 3752 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3753 } 3754 PetscFunctionReturn(0); 3755 } 3756 3757 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3758 { 3759 PetscFunctionBegin; 3760 if (subdm) PetscCall(DMClone(dm, subdm)); 3761 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3762 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3763 if (dm->useNatural && dm->sfMigration) { 3764 PetscSF sfMigrationInv,sfNatural; 3765 PetscSection section, sectionSeq; 3766 3767 (*subdm)->sfMigration = dm->sfMigration; 3768 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3769 PetscCall(DMGetLocalSection((*subdm), §ion)); 3770 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3771 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3772 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3773 3774 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3775 (*subdm)->sfNatural = sfNatural; 3776 PetscCall(PetscSectionDestroy(§ionSeq)); 3777 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3778 } 3779 PetscFunctionReturn(0); 3780 } 3781 3782 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3783 { 3784 PetscInt i = 0; 3785 3786 PetscFunctionBegin; 3787 PetscCall(DMClone(dms[0], superdm)); 3788 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3789 (*superdm)->useNatural = PETSC_FALSE; 3790 for (i = 0; i < len; i++) { 3791 if (dms[i]->useNatural && dms[i]->sfMigration) { 3792 PetscSF sfMigrationInv,sfNatural; 3793 PetscSection section, sectionSeq; 3794 3795 (*superdm)->sfMigration = dms[i]->sfMigration; 3796 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3797 (*superdm)->useNatural = PETSC_TRUE; 3798 PetscCall(DMGetLocalSection((*superdm), §ion)); 3799 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3800 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3801 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3802 3803 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3804 (*superdm)->sfNatural = sfNatural; 3805 PetscCall(PetscSectionDestroy(§ionSeq)); 3806 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3807 break; 3808 } 3809 } 3810 PetscFunctionReturn(0); 3811 } 3812 3813 /*@ 3814 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3815 3816 Not collective 3817 3818 Input Parameter: 3819 . mesh - The DMPlex 3820 3821 Output Parameter: 3822 3823 Note: 3824 This should be called after all calls to DMPlexSetCone() 3825 3826 Level: beginner 3827 3828 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3829 @*/ 3830 PetscErrorCode DMPlexSymmetrize(DM dm) 3831 { 3832 DM_Plex *mesh = (DM_Plex*) dm->data; 3833 PetscInt *offsets; 3834 PetscInt supportSize; 3835 PetscInt pStart, pEnd, p; 3836 3837 PetscFunctionBegin; 3838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3839 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3840 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3841 /* Calculate support sizes */ 3842 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3843 for (p = pStart; p < pEnd; ++p) { 3844 PetscInt dof, off, c; 3845 3846 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3847 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3848 for (c = off; c < off+dof; ++c) { 3849 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3850 } 3851 } 3852 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3853 /* Calculate supports */ 3854 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3855 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3856 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3857 for (p = pStart; p < pEnd; ++p) { 3858 PetscInt dof, off, c; 3859 3860 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3861 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3862 for (c = off; c < off+dof; ++c) { 3863 const PetscInt q = mesh->cones[c]; 3864 PetscInt offS; 3865 3866 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3867 3868 mesh->supports[offS+offsets[q]] = p; 3869 ++offsets[q]; 3870 } 3871 } 3872 PetscCall(PetscFree(offsets)); 3873 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3874 PetscFunctionReturn(0); 3875 } 3876 3877 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3878 { 3879 IS stratumIS; 3880 3881 PetscFunctionBegin; 3882 if (pStart >= pEnd) PetscFunctionReturn(0); 3883 if (PetscDefined(USE_DEBUG)) { 3884 PetscInt qStart, qEnd, numLevels, level; 3885 PetscBool overlap = PETSC_FALSE; 3886 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3887 for (level = 0; level < numLevels; level++) { 3888 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3889 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3890 } 3891 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); 3892 } 3893 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3894 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3895 PetscCall(ISDestroy(&stratumIS)); 3896 PetscFunctionReturn(0); 3897 } 3898 3899 /*@ 3900 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3901 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3902 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3903 the DAG. 3904 3905 Collective on dm 3906 3907 Input Parameter: 3908 . mesh - The DMPlex 3909 3910 Output Parameter: 3911 3912 Notes: 3913 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3914 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3915 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3916 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3917 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3918 3919 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3920 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3921 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 3922 to interpolate only that one (e0), so that 3923 $ cone(c0) = {e0, v2} 3924 $ cone(e0) = {v0, v1} 3925 If DMPlexStratify() is run on this mesh, it will give depths 3926 $ depth 0 = {v0, v1, v2} 3927 $ depth 1 = {e0, c0} 3928 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3929 3930 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3931 3932 Level: beginner 3933 3934 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3935 @*/ 3936 PetscErrorCode DMPlexStratify(DM dm) 3937 { 3938 DM_Plex *mesh = (DM_Plex*) dm->data; 3939 DMLabel label; 3940 PetscInt pStart, pEnd, p; 3941 PetscInt numRoots = 0, numLeaves = 0; 3942 3943 PetscFunctionBegin; 3944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3945 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3946 3947 /* Create depth label */ 3948 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3949 PetscCall(DMCreateLabel(dm, "depth")); 3950 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3951 3952 { 3953 /* Initialize roots and count leaves */ 3954 PetscInt sMin = PETSC_MAX_INT; 3955 PetscInt sMax = PETSC_MIN_INT; 3956 PetscInt coneSize, supportSize; 3957 3958 for (p = pStart; p < pEnd; ++p) { 3959 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3960 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3961 if (!coneSize && supportSize) { 3962 sMin = PetscMin(p, sMin); 3963 sMax = PetscMax(p, sMax); 3964 ++numRoots; 3965 } else if (!supportSize && coneSize) { 3966 ++numLeaves; 3967 } else if (!supportSize && !coneSize) { 3968 /* Isolated points */ 3969 sMin = PetscMin(p, sMin); 3970 sMax = PetscMax(p, sMax); 3971 } 3972 } 3973 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3974 } 3975 3976 if (numRoots + numLeaves == (pEnd - pStart)) { 3977 PetscInt sMin = PETSC_MAX_INT; 3978 PetscInt sMax = PETSC_MIN_INT; 3979 PetscInt coneSize, supportSize; 3980 3981 for (p = pStart; p < pEnd; ++p) { 3982 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3983 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3984 if (!supportSize && coneSize) { 3985 sMin = PetscMin(p, sMin); 3986 sMax = PetscMax(p, sMax); 3987 } 3988 } 3989 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3990 } else { 3991 PetscInt level = 0; 3992 PetscInt qStart, qEnd, q; 3993 3994 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3995 while (qEnd > qStart) { 3996 PetscInt sMin = PETSC_MAX_INT; 3997 PetscInt sMax = PETSC_MIN_INT; 3998 3999 for (q = qStart; q < qEnd; ++q) { 4000 const PetscInt *support; 4001 PetscInt supportSize, s; 4002 4003 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4004 PetscCall(DMPlexGetSupport(dm, q, &support)); 4005 for (s = 0; s < supportSize; ++s) { 4006 sMin = PetscMin(support[s], sMin); 4007 sMax = PetscMax(support[s], sMax); 4008 } 4009 } 4010 PetscCall(DMLabelGetNumValues(label, &level)); 4011 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4012 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4013 } 4014 } 4015 { /* just in case there is an empty process */ 4016 PetscInt numValues, maxValues = 0, v; 4017 4018 PetscCall(DMLabelGetNumValues(label, &numValues)); 4019 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4020 for (v = numValues; v < maxValues; v++) { 4021 PetscCall(DMLabelAddStratum(label, v)); 4022 } 4023 } 4024 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4025 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4026 PetscFunctionReturn(0); 4027 } 4028 4029 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4030 { 4031 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4032 PetscInt dim, depth, pheight, coneSize; 4033 4034 PetscFunctionBeginHot; 4035 PetscCall(DMGetDimension(dm, &dim)); 4036 PetscCall(DMPlexGetDepth(dm, &depth)); 4037 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4038 pheight = depth - pdepth; 4039 if (depth <= 1) { 4040 switch (pdepth) { 4041 case 0: ct = DM_POLYTOPE_POINT;break; 4042 case 1: 4043 switch (coneSize) { 4044 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4045 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4046 case 4: 4047 switch (dim) { 4048 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4049 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4050 default: break; 4051 } 4052 break; 4053 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4054 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4055 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4056 default: break; 4057 } 4058 } 4059 } else { 4060 if (pdepth == 0) { 4061 ct = DM_POLYTOPE_POINT; 4062 } else if (pheight == 0) { 4063 switch (dim) { 4064 case 1: 4065 switch (coneSize) { 4066 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4067 default: break; 4068 } 4069 break; 4070 case 2: 4071 switch (coneSize) { 4072 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4073 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4074 default: break; 4075 } 4076 break; 4077 case 3: 4078 switch (coneSize) { 4079 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4080 case 5: 4081 { 4082 const PetscInt *cone; 4083 PetscInt faceConeSize; 4084 4085 PetscCall(DMPlexGetCone(dm, p, &cone)); 4086 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4087 switch (faceConeSize) { 4088 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4089 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4090 } 4091 } 4092 break; 4093 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4094 default: break; 4095 } 4096 break; 4097 default: break; 4098 } 4099 } else if (pheight > 0) { 4100 switch (coneSize) { 4101 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4102 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4103 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4104 default: break; 4105 } 4106 } 4107 } 4108 *pt = ct; 4109 PetscFunctionReturn(0); 4110 } 4111 4112 /*@ 4113 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4114 4115 Collective on dm 4116 4117 Input Parameter: 4118 . mesh - The DMPlex 4119 4120 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4121 4122 Level: developer 4123 4124 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4125 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4126 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4127 4128 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4129 @*/ 4130 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4131 { 4132 DM_Plex *mesh; 4133 DMLabel ctLabel; 4134 PetscInt pStart, pEnd, p; 4135 4136 PetscFunctionBegin; 4137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4138 mesh = (DM_Plex *) dm->data; 4139 PetscCall(DMCreateLabel(dm, "celltype")); 4140 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4141 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4142 for (p = pStart; p < pEnd; ++p) { 4143 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4144 PetscInt pdepth; 4145 4146 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4147 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4148 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4149 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4150 } 4151 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4152 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4153 PetscFunctionReturn(0); 4154 } 4155 4156 /*@C 4157 DMPlexGetJoin - Get an array for the join of the set of points 4158 4159 Not Collective 4160 4161 Input Parameters: 4162 + dm - The DMPlex object 4163 . numPoints - The number of input points for the join 4164 - points - The input points 4165 4166 Output Parameters: 4167 + numCoveredPoints - The number of points in the join 4168 - coveredPoints - The points in the join 4169 4170 Level: intermediate 4171 4172 Note: Currently, this is restricted to a single level join 4173 4174 Fortran Notes: 4175 Since it returns an array, this routine is only available in Fortran 90, and you must 4176 include petsc.h90 in your code. 4177 4178 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4179 4180 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4181 @*/ 4182 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4183 { 4184 DM_Plex *mesh = (DM_Plex*) dm->data; 4185 PetscInt *join[2]; 4186 PetscInt joinSize, i = 0; 4187 PetscInt dof, off, p, c, m; 4188 PetscInt maxSupportSize; 4189 4190 PetscFunctionBegin; 4191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4192 PetscValidIntPointer(points, 3); 4193 PetscValidIntPointer(numCoveredPoints, 4); 4194 PetscValidPointer(coveredPoints, 5); 4195 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4196 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4197 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4198 /* Copy in support of first point */ 4199 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4200 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4201 for (joinSize = 0; joinSize < dof; ++joinSize) { 4202 join[i][joinSize] = mesh->supports[off+joinSize]; 4203 } 4204 /* Check each successive support */ 4205 for (p = 1; p < numPoints; ++p) { 4206 PetscInt newJoinSize = 0; 4207 4208 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4209 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4210 for (c = 0; c < dof; ++c) { 4211 const PetscInt point = mesh->supports[off+c]; 4212 4213 for (m = 0; m < joinSize; ++m) { 4214 if (point == join[i][m]) { 4215 join[1-i][newJoinSize++] = point; 4216 break; 4217 } 4218 } 4219 } 4220 joinSize = newJoinSize; 4221 i = 1-i; 4222 } 4223 *numCoveredPoints = joinSize; 4224 *coveredPoints = join[i]; 4225 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4226 PetscFunctionReturn(0); 4227 } 4228 4229 /*@C 4230 DMPlexRestoreJoin - Restore an array for the join of the set of points 4231 4232 Not Collective 4233 4234 Input Parameters: 4235 + dm - The DMPlex object 4236 . numPoints - The number of input points for the join 4237 - points - The input points 4238 4239 Output Parameters: 4240 + numCoveredPoints - The number of points in the join 4241 - coveredPoints - The points in the join 4242 4243 Fortran Notes: 4244 Since it returns an array, this routine is only available in Fortran 90, and you must 4245 include petsc.h90 in your code. 4246 4247 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4248 4249 Level: intermediate 4250 4251 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4252 @*/ 4253 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4254 { 4255 PetscFunctionBegin; 4256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4257 if (points) PetscValidIntPointer(points,3); 4258 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4259 PetscValidPointer(coveredPoints, 5); 4260 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4261 if (numCoveredPoints) *numCoveredPoints = 0; 4262 PetscFunctionReturn(0); 4263 } 4264 4265 /*@C 4266 DMPlexGetFullJoin - Get an array for the join of the set of points 4267 4268 Not Collective 4269 4270 Input Parameters: 4271 + dm - The DMPlex object 4272 . numPoints - The number of input points for the join 4273 - points - The input points 4274 4275 Output Parameters: 4276 + numCoveredPoints - The number of points in the join 4277 - coveredPoints - The points in the join 4278 4279 Fortran Notes: 4280 Since it returns an array, this routine is only available in Fortran 90, and you must 4281 include petsc.h90 in your code. 4282 4283 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4284 4285 Level: intermediate 4286 4287 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4288 @*/ 4289 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4290 { 4291 PetscInt *offsets, **closures; 4292 PetscInt *join[2]; 4293 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4294 PetscInt p, d, c, m, ms; 4295 4296 PetscFunctionBegin; 4297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4298 PetscValidIntPointer(points, 3); 4299 PetscValidIntPointer(numCoveredPoints, 4); 4300 PetscValidPointer(coveredPoints, 5); 4301 4302 PetscCall(DMPlexGetDepth(dm, &depth)); 4303 PetscCall(PetscCalloc1(numPoints, &closures)); 4304 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4305 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4306 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4307 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4308 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4309 4310 for (p = 0; p < numPoints; ++p) { 4311 PetscInt closureSize; 4312 4313 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4314 4315 offsets[p*(depth+2)+0] = 0; 4316 for (d = 0; d < depth+1; ++d) { 4317 PetscInt pStart, pEnd, i; 4318 4319 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4320 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4321 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4322 offsets[p*(depth+2)+d+1] = i; 4323 break; 4324 } 4325 } 4326 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4327 } 4328 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); 4329 } 4330 for (d = 0; d < depth+1; ++d) { 4331 PetscInt dof; 4332 4333 /* Copy in support of first point */ 4334 dof = offsets[d+1] - offsets[d]; 4335 for (joinSize = 0; joinSize < dof; ++joinSize) { 4336 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4337 } 4338 /* Check each successive cone */ 4339 for (p = 1; p < numPoints && joinSize; ++p) { 4340 PetscInt newJoinSize = 0; 4341 4342 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4343 for (c = 0; c < dof; ++c) { 4344 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4345 4346 for (m = 0; m < joinSize; ++m) { 4347 if (point == join[i][m]) { 4348 join[1-i][newJoinSize++] = point; 4349 break; 4350 } 4351 } 4352 } 4353 joinSize = newJoinSize; 4354 i = 1-i; 4355 } 4356 if (joinSize) break; 4357 } 4358 *numCoveredPoints = joinSize; 4359 *coveredPoints = join[i]; 4360 for (p = 0; p < numPoints; ++p) { 4361 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4362 } 4363 PetscCall(PetscFree(closures)); 4364 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4365 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4366 PetscFunctionReturn(0); 4367 } 4368 4369 /*@C 4370 DMPlexGetMeet - Get an array for the meet of the set of points 4371 4372 Not Collective 4373 4374 Input Parameters: 4375 + dm - The DMPlex object 4376 . numPoints - The number of input points for the meet 4377 - points - The input points 4378 4379 Output Parameters: 4380 + numCoveredPoints - The number of points in the meet 4381 - coveredPoints - The points in the meet 4382 4383 Level: intermediate 4384 4385 Note: Currently, this is restricted to a single level meet 4386 4387 Fortran Notes: 4388 Since it returns an array, this routine is only available in Fortran 90, and you must 4389 include petsc.h90 in your code. 4390 4391 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4392 4393 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4394 @*/ 4395 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4396 { 4397 DM_Plex *mesh = (DM_Plex*) dm->data; 4398 PetscInt *meet[2]; 4399 PetscInt meetSize, i = 0; 4400 PetscInt dof, off, p, c, m; 4401 PetscInt maxConeSize; 4402 4403 PetscFunctionBegin; 4404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4405 PetscValidIntPointer(points, 3); 4406 PetscValidIntPointer(numCoveringPoints, 4); 4407 PetscValidPointer(coveringPoints, 5); 4408 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4409 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4410 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4411 /* Copy in cone of first point */ 4412 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4413 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4414 for (meetSize = 0; meetSize < dof; ++meetSize) { 4415 meet[i][meetSize] = mesh->cones[off+meetSize]; 4416 } 4417 /* Check each successive cone */ 4418 for (p = 1; p < numPoints; ++p) { 4419 PetscInt newMeetSize = 0; 4420 4421 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4422 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4423 for (c = 0; c < dof; ++c) { 4424 const PetscInt point = mesh->cones[off+c]; 4425 4426 for (m = 0; m < meetSize; ++m) { 4427 if (point == meet[i][m]) { 4428 meet[1-i][newMeetSize++] = point; 4429 break; 4430 } 4431 } 4432 } 4433 meetSize = newMeetSize; 4434 i = 1-i; 4435 } 4436 *numCoveringPoints = meetSize; 4437 *coveringPoints = meet[i]; 4438 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4439 PetscFunctionReturn(0); 4440 } 4441 4442 /*@C 4443 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4444 4445 Not Collective 4446 4447 Input Parameters: 4448 + dm - The DMPlex object 4449 . numPoints - The number of input points for the meet 4450 - points - The input points 4451 4452 Output Parameters: 4453 + numCoveredPoints - The number of points in the meet 4454 - coveredPoints - The points in the meet 4455 4456 Level: intermediate 4457 4458 Fortran Notes: 4459 Since it returns an array, this routine is only available in Fortran 90, and you must 4460 include petsc.h90 in your code. 4461 4462 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4463 4464 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4465 @*/ 4466 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4467 { 4468 PetscFunctionBegin; 4469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4470 if (points) PetscValidIntPointer(points,3); 4471 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4472 PetscValidPointer(coveredPoints,5); 4473 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4474 if (numCoveredPoints) *numCoveredPoints = 0; 4475 PetscFunctionReturn(0); 4476 } 4477 4478 /*@C 4479 DMPlexGetFullMeet - Get an array for the meet of the set of points 4480 4481 Not Collective 4482 4483 Input Parameters: 4484 + dm - The DMPlex object 4485 . numPoints - The number of input points for the meet 4486 - points - The input points 4487 4488 Output Parameters: 4489 + numCoveredPoints - The number of points in the meet 4490 - coveredPoints - The points in the meet 4491 4492 Level: intermediate 4493 4494 Fortran Notes: 4495 Since it returns an array, this routine is only available in Fortran 90, and you must 4496 include petsc.h90 in your code. 4497 4498 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4499 4500 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4501 @*/ 4502 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4503 { 4504 PetscInt *offsets, **closures; 4505 PetscInt *meet[2]; 4506 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4507 PetscInt p, h, c, m, mc; 4508 4509 PetscFunctionBegin; 4510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4511 PetscValidIntPointer(points, 3); 4512 PetscValidIntPointer(numCoveredPoints, 4); 4513 PetscValidPointer(coveredPoints, 5); 4514 4515 PetscCall(DMPlexGetDepth(dm, &height)); 4516 PetscCall(PetscMalloc1(numPoints, &closures)); 4517 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4518 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4519 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4520 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4521 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4522 4523 for (p = 0; p < numPoints; ++p) { 4524 PetscInt closureSize; 4525 4526 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4527 4528 offsets[p*(height+2)+0] = 0; 4529 for (h = 0; h < height+1; ++h) { 4530 PetscInt pStart, pEnd, i; 4531 4532 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4533 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4534 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4535 offsets[p*(height+2)+h+1] = i; 4536 break; 4537 } 4538 } 4539 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4540 } 4541 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); 4542 } 4543 for (h = 0; h < height+1; ++h) { 4544 PetscInt dof; 4545 4546 /* Copy in cone of first point */ 4547 dof = offsets[h+1] - offsets[h]; 4548 for (meetSize = 0; meetSize < dof; ++meetSize) { 4549 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4550 } 4551 /* Check each successive cone */ 4552 for (p = 1; p < numPoints && meetSize; ++p) { 4553 PetscInt newMeetSize = 0; 4554 4555 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4556 for (c = 0; c < dof; ++c) { 4557 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4558 4559 for (m = 0; m < meetSize; ++m) { 4560 if (point == meet[i][m]) { 4561 meet[1-i][newMeetSize++] = point; 4562 break; 4563 } 4564 } 4565 } 4566 meetSize = newMeetSize; 4567 i = 1-i; 4568 } 4569 if (meetSize) break; 4570 } 4571 *numCoveredPoints = meetSize; 4572 *coveredPoints = meet[i]; 4573 for (p = 0; p < numPoints; ++p) { 4574 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4575 } 4576 PetscCall(PetscFree(closures)); 4577 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4578 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4579 PetscFunctionReturn(0); 4580 } 4581 4582 /*@C 4583 DMPlexEqual - Determine if two DMs have the same topology 4584 4585 Not Collective 4586 4587 Input Parameters: 4588 + dmA - A DMPlex object 4589 - dmB - A DMPlex object 4590 4591 Output Parameters: 4592 . equal - PETSC_TRUE if the topologies are identical 4593 4594 Level: intermediate 4595 4596 Notes: 4597 We are not solving graph isomorphism, so we do not permutation. 4598 4599 .seealso: `DMPlexGetCone()` 4600 @*/ 4601 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4602 { 4603 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4604 4605 PetscFunctionBegin; 4606 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4607 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4608 PetscValidBoolPointer(equal, 3); 4609 4610 *equal = PETSC_FALSE; 4611 PetscCall(DMPlexGetDepth(dmA, &depth)); 4612 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4613 if (depth != depthB) PetscFunctionReturn(0); 4614 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4615 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4616 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4617 for (p = pStart; p < pEnd; ++p) { 4618 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4619 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4620 4621 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4622 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4623 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4624 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4625 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4626 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4627 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4628 for (c = 0; c < coneSize; ++c) { 4629 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4630 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4631 } 4632 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4633 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4634 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4635 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4636 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4637 for (s = 0; s < supportSize; ++s) { 4638 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4639 } 4640 } 4641 *equal = PETSC_TRUE; 4642 PetscFunctionReturn(0); 4643 } 4644 4645 /*@C 4646 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4647 4648 Not Collective 4649 4650 Input Parameters: 4651 + dm - The DMPlex 4652 . cellDim - The cell dimension 4653 - numCorners - The number of vertices on a cell 4654 4655 Output Parameters: 4656 . numFaceVertices - The number of vertices on a face 4657 4658 Level: developer 4659 4660 Notes: 4661 Of course this can only work for a restricted set of symmetric shapes 4662 4663 .seealso: `DMPlexGetCone()` 4664 @*/ 4665 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4666 { 4667 MPI_Comm comm; 4668 4669 PetscFunctionBegin; 4670 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4671 PetscValidIntPointer(numFaceVertices,4); 4672 switch (cellDim) { 4673 case 0: 4674 *numFaceVertices = 0; 4675 break; 4676 case 1: 4677 *numFaceVertices = 1; 4678 break; 4679 case 2: 4680 switch (numCorners) { 4681 case 3: /* triangle */ 4682 *numFaceVertices = 2; /* Edge has 2 vertices */ 4683 break; 4684 case 4: /* quadrilateral */ 4685 *numFaceVertices = 2; /* Edge has 2 vertices */ 4686 break; 4687 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4688 *numFaceVertices = 3; /* Edge has 3 vertices */ 4689 break; 4690 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4691 *numFaceVertices = 3; /* Edge has 3 vertices */ 4692 break; 4693 default: 4694 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4695 } 4696 break; 4697 case 3: 4698 switch (numCorners) { 4699 case 4: /* tetradehdron */ 4700 *numFaceVertices = 3; /* Face has 3 vertices */ 4701 break; 4702 case 6: /* tet cohesive cells */ 4703 *numFaceVertices = 4; /* Face has 4 vertices */ 4704 break; 4705 case 8: /* hexahedron */ 4706 *numFaceVertices = 4; /* Face has 4 vertices */ 4707 break; 4708 case 9: /* tet cohesive Lagrange cells */ 4709 *numFaceVertices = 6; /* Face has 6 vertices */ 4710 break; 4711 case 10: /* quadratic tetrahedron */ 4712 *numFaceVertices = 6; /* Face has 6 vertices */ 4713 break; 4714 case 12: /* hex cohesive Lagrange cells */ 4715 *numFaceVertices = 6; /* Face has 6 vertices */ 4716 break; 4717 case 18: /* quadratic tet cohesive Lagrange cells */ 4718 *numFaceVertices = 6; /* Face has 6 vertices */ 4719 break; 4720 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4721 *numFaceVertices = 9; /* Face has 9 vertices */ 4722 break; 4723 default: 4724 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4725 } 4726 break; 4727 default: 4728 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4729 } 4730 PetscFunctionReturn(0); 4731 } 4732 4733 /*@ 4734 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4735 4736 Not Collective 4737 4738 Input Parameter: 4739 . dm - The DMPlex object 4740 4741 Output Parameter: 4742 . depthLabel - The DMLabel recording point depth 4743 4744 Level: developer 4745 4746 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4747 @*/ 4748 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4749 { 4750 PetscFunctionBegin; 4751 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4752 PetscValidPointer(depthLabel, 2); 4753 *depthLabel = dm->depthLabel; 4754 PetscFunctionReturn(0); 4755 } 4756 4757 /*@ 4758 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4759 4760 Not Collective 4761 4762 Input Parameter: 4763 . dm - The DMPlex object 4764 4765 Output Parameter: 4766 . depth - The number of strata (breadth first levels) in the DAG 4767 4768 Level: developer 4769 4770 Notes: 4771 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4772 The point depth is described more in detail in DMPlexGetDepthStratum(). 4773 An empty mesh gives -1. 4774 4775 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4776 @*/ 4777 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4778 { 4779 DMLabel label; 4780 PetscInt d = 0; 4781 4782 PetscFunctionBegin; 4783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4784 PetscValidIntPointer(depth, 2); 4785 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4786 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4787 *depth = d-1; 4788 PetscFunctionReturn(0); 4789 } 4790 4791 /*@ 4792 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4793 4794 Not Collective 4795 4796 Input Parameters: 4797 + dm - The DMPlex object 4798 - depth - The requested depth 4799 4800 Output Parameters: 4801 + start - The first point at this depth 4802 - end - One beyond the last point at this depth 4803 4804 Notes: 4805 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4806 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4807 higher dimension, e.g., "edges". 4808 4809 Level: developer 4810 4811 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4812 @*/ 4813 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4814 { 4815 DMLabel label; 4816 PetscInt pStart, pEnd; 4817 4818 PetscFunctionBegin; 4819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4820 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4821 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4822 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4823 if (pStart == pEnd) PetscFunctionReturn(0); 4824 if (depth < 0) { 4825 if (start) *start = pStart; 4826 if (end) *end = pEnd; 4827 PetscFunctionReturn(0); 4828 } 4829 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4830 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4831 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4832 PetscFunctionReturn(0); 4833 } 4834 4835 /*@ 4836 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4837 4838 Not Collective 4839 4840 Input Parameters: 4841 + dm - The DMPlex object 4842 - height - The requested height 4843 4844 Output Parameters: 4845 + start - The first point at this height 4846 - end - One beyond the last point at this height 4847 4848 Notes: 4849 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4850 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4851 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4852 4853 Level: developer 4854 4855 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4856 @*/ 4857 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4858 { 4859 DMLabel label; 4860 PetscInt depth, pStart, pEnd; 4861 4862 PetscFunctionBegin; 4863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4864 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4865 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4866 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4867 if (pStart == pEnd) PetscFunctionReturn(0); 4868 if (height < 0) { 4869 if (start) *start = pStart; 4870 if (end) *end = pEnd; 4871 PetscFunctionReturn(0); 4872 } 4873 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4874 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4875 PetscCall(DMLabelGetNumValues(label, &depth)); 4876 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4877 PetscFunctionReturn(0); 4878 } 4879 4880 /*@ 4881 DMPlexGetPointDepth - Get the depth of a given point 4882 4883 Not Collective 4884 4885 Input Parameters: 4886 + dm - The DMPlex object 4887 - point - The point 4888 4889 Output Parameter: 4890 . depth - The depth of the point 4891 4892 Level: intermediate 4893 4894 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4895 @*/ 4896 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4897 { 4898 PetscFunctionBegin; 4899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4900 PetscValidIntPointer(depth, 3); 4901 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4902 PetscFunctionReturn(0); 4903 } 4904 4905 /*@ 4906 DMPlexGetPointHeight - Get the height of a given point 4907 4908 Not Collective 4909 4910 Input Parameters: 4911 + dm - The DMPlex object 4912 - point - The point 4913 4914 Output Parameter: 4915 . height - The height of the point 4916 4917 Level: intermediate 4918 4919 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4920 @*/ 4921 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4922 { 4923 PetscInt n, pDepth; 4924 4925 PetscFunctionBegin; 4926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4927 PetscValidIntPointer(height, 3); 4928 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4929 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4930 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4931 PetscFunctionReturn(0); 4932 } 4933 4934 /*@ 4935 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4936 4937 Not Collective 4938 4939 Input Parameter: 4940 . dm - The DMPlex object 4941 4942 Output Parameter: 4943 . celltypeLabel - The DMLabel recording cell polytope type 4944 4945 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4946 DMCreateLabel(dm, "celltype") beforehand. 4947 4948 Level: developer 4949 4950 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4951 @*/ 4952 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4953 { 4954 PetscFunctionBegin; 4955 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4956 PetscValidPointer(celltypeLabel, 2); 4957 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4958 *celltypeLabel = dm->celltypeLabel; 4959 PetscFunctionReturn(0); 4960 } 4961 4962 /*@ 4963 DMPlexGetCellType - Get the polytope type of a given cell 4964 4965 Not Collective 4966 4967 Input Parameters: 4968 + dm - The DMPlex object 4969 - cell - The cell 4970 4971 Output Parameter: 4972 . celltype - The polytope type of the cell 4973 4974 Level: intermediate 4975 4976 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4977 @*/ 4978 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4979 { 4980 DMLabel label; 4981 PetscInt ct; 4982 4983 PetscFunctionBegin; 4984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4985 PetscValidPointer(celltype, 3); 4986 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4987 PetscCall(DMLabelGetValue(label, cell, &ct)); 4988 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4989 *celltype = (DMPolytopeType) ct; 4990 PetscFunctionReturn(0); 4991 } 4992 4993 /*@ 4994 DMPlexSetCellType - Set the polytope type of a given cell 4995 4996 Not Collective 4997 4998 Input Parameters: 4999 + dm - The DMPlex object 5000 . cell - The cell 5001 - celltype - The polytope type of the cell 5002 5003 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5004 is executed. This function will override the computed type. However, if automatic classification will not succeed 5005 and a user wants to manually specify all types, the classification must be disabled by calling 5006 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5007 5008 Level: advanced 5009 5010 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5011 @*/ 5012 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5013 { 5014 DMLabel label; 5015 5016 PetscFunctionBegin; 5017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5018 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5019 PetscCall(DMLabelSetValue(label, cell, celltype)); 5020 PetscFunctionReturn(0); 5021 } 5022 5023 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5024 { 5025 PetscSection section, s; 5026 Mat m; 5027 PetscInt maxHeight; 5028 5029 PetscFunctionBegin; 5030 PetscCall(DMClone(dm, cdm)); 5031 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5032 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5033 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5034 PetscCall(DMSetLocalSection(*cdm, section)); 5035 PetscCall(PetscSectionDestroy(§ion)); 5036 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5037 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5038 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5039 PetscCall(PetscSectionDestroy(&s)); 5040 PetscCall(MatDestroy(&m)); 5041 5042 PetscCall(DMSetNumFields(*cdm, 1)); 5043 PetscCall(DMCreateDS(*cdm)); 5044 PetscFunctionReturn(0); 5045 } 5046 5047 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5048 { 5049 Vec coordsLocal, cellCoordsLocal; 5050 DM coordsDM, cellCoordsDM; 5051 5052 PetscFunctionBegin; 5053 *field = NULL; 5054 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5055 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5056 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5057 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5058 if (coordsLocal && coordsDM) { 5059 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5060 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5061 } 5062 PetscFunctionReturn(0); 5063 } 5064 5065 /*@C 5066 DMPlexGetConeSection - Return a section which describes the layout of cone data 5067 5068 Not Collective 5069 5070 Input Parameters: 5071 . dm - The DMPlex object 5072 5073 Output Parameter: 5074 . section - The PetscSection object 5075 5076 Level: developer 5077 5078 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5079 @*/ 5080 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5081 { 5082 DM_Plex *mesh = (DM_Plex*) dm->data; 5083 5084 PetscFunctionBegin; 5085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5086 if (section) *section = mesh->coneSection; 5087 PetscFunctionReturn(0); 5088 } 5089 5090 /*@C 5091 DMPlexGetSupportSection - Return a section which describes the layout of support data 5092 5093 Not Collective 5094 5095 Input Parameters: 5096 . dm - The DMPlex object 5097 5098 Output Parameter: 5099 . section - The PetscSection object 5100 5101 Level: developer 5102 5103 .seealso: `DMPlexGetConeSection()` 5104 @*/ 5105 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5106 { 5107 DM_Plex *mesh = (DM_Plex*) dm->data; 5108 5109 PetscFunctionBegin; 5110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5111 if (section) *section = mesh->supportSection; 5112 PetscFunctionReturn(0); 5113 } 5114 5115 /*@C 5116 DMPlexGetCones - Return cone data 5117 5118 Not Collective 5119 5120 Input Parameters: 5121 . dm - The DMPlex object 5122 5123 Output Parameter: 5124 . cones - The cone for each point 5125 5126 Level: developer 5127 5128 .seealso: `DMPlexGetConeSection()` 5129 @*/ 5130 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5131 { 5132 DM_Plex *mesh = (DM_Plex*) dm->data; 5133 5134 PetscFunctionBegin; 5135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5136 if (cones) *cones = mesh->cones; 5137 PetscFunctionReturn(0); 5138 } 5139 5140 /*@C 5141 DMPlexGetConeOrientations - Return cone orientation data 5142 5143 Not Collective 5144 5145 Input Parameters: 5146 . dm - The DMPlex object 5147 5148 Output Parameter: 5149 . coneOrientations - The array of cone orientations for all points 5150 5151 Level: developer 5152 5153 Notes: 5154 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5155 5156 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5157 5158 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5159 @*/ 5160 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5161 { 5162 DM_Plex *mesh = (DM_Plex*) dm->data; 5163 5164 PetscFunctionBegin; 5165 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5166 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5167 PetscFunctionReturn(0); 5168 } 5169 5170 /******************************** FEM Support **********************************/ 5171 5172 /* 5173 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5174 representing a line in the section. 5175 */ 5176 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5177 { 5178 PetscFunctionBeginHot; 5179 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5180 if (line < 0) { 5181 *k = 0; 5182 *Nc = 0; 5183 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5184 *k = 1; 5185 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5186 /* An order k SEM disc has k-1 dofs on an edge */ 5187 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5188 *k = *k / *Nc + 1; 5189 } 5190 PetscFunctionReturn(0); 5191 } 5192 5193 /*@ 5194 5195 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5196 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5197 section provided (or the section of the DM). 5198 5199 Input Parameters: 5200 + dm - The DM 5201 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5202 - section - The PetscSection to reorder, or NULL for the default section 5203 5204 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5205 degree of the basis. 5206 5207 Example: 5208 A typical interpolated single-quad mesh might order points as 5209 .vb 5210 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5211 5212 v4 -- e6 -- v3 5213 | | 5214 e7 c0 e8 5215 | | 5216 v1 -- e5 -- v2 5217 .ve 5218 5219 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5220 dofs in the order of points, e.g., 5221 .vb 5222 c0 -> [0,1,2,3] 5223 v1 -> [4] 5224 ... 5225 e5 -> [8, 9] 5226 .ve 5227 5228 which corresponds to the dofs 5229 .vb 5230 6 10 11 7 5231 13 2 3 15 5232 12 0 1 14 5233 4 8 9 5 5234 .ve 5235 5236 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5237 .vb 5238 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5239 .ve 5240 5241 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5242 .vb 5243 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5244 .ve 5245 5246 Level: developer 5247 5248 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5249 @*/ 5250 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5251 { 5252 DMLabel label; 5253 PetscInt dim, depth = -1, eStart = -1, Nf; 5254 PetscBool vertexchart; 5255 5256 PetscFunctionBegin; 5257 PetscCall(DMGetDimension(dm, &dim)); 5258 if (dim < 1) PetscFunctionReturn(0); 5259 if (point < 0) { 5260 PetscInt sStart,sEnd; 5261 5262 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5263 point = sEnd-sStart ? sStart : point; 5264 } 5265 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5266 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5267 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5268 if (depth == 1) {eStart = point;} 5269 else if (depth == dim) { 5270 const PetscInt *cone; 5271 5272 PetscCall(DMPlexGetCone(dm, point, &cone)); 5273 if (dim == 2) eStart = cone[0]; 5274 else if (dim == 3) { 5275 const PetscInt *cone2; 5276 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5277 eStart = cone2[0]; 5278 } 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); 5279 } 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); 5280 { /* Determine whether the chart covers all points or just vertices. */ 5281 PetscInt pStart,pEnd,cStart,cEnd; 5282 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5283 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5284 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5285 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5286 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5287 } 5288 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5289 for (PetscInt d=1; d<=dim; d++) { 5290 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5291 PetscInt *perm; 5292 5293 for (f = 0; f < Nf; ++f) { 5294 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5295 size += PetscPowInt(k+1, d)*Nc; 5296 } 5297 PetscCall(PetscMalloc1(size, &perm)); 5298 for (f = 0; f < Nf; ++f) { 5299 switch (d) { 5300 case 1: 5301 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5302 /* 5303 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5304 We want [ vtx0; edge of length k-1; vtx1 ] 5305 */ 5306 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5307 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5308 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5309 foffset = offset; 5310 break; 5311 case 2: 5312 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5313 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5314 /* The SEM order is 5315 5316 v_lb, {e_b}, v_rb, 5317 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5318 v_lt, reverse {e_t}, v_rt 5319 */ 5320 { 5321 const PetscInt of = 0; 5322 const PetscInt oeb = of + PetscSqr(k-1); 5323 const PetscInt oer = oeb + (k-1); 5324 const PetscInt oet = oer + (k-1); 5325 const PetscInt oel = oet + (k-1); 5326 const PetscInt ovlb = oel + (k-1); 5327 const PetscInt ovrb = ovlb + 1; 5328 const PetscInt ovrt = ovrb + 1; 5329 const PetscInt ovlt = ovrt + 1; 5330 PetscInt o; 5331 5332 /* bottom */ 5333 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5334 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5335 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5336 /* middle */ 5337 for (i = 0; i < k-1; ++i) { 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5339 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; 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5341 } 5342 /* top */ 5343 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5344 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5345 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5346 foffset = offset; 5347 } 5348 break; 5349 case 3: 5350 /* The original hex closure is 5351 5352 {c, 5353 f_b, f_t, f_f, f_b, f_r, f_l, 5354 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5355 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5356 */ 5357 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5358 /* The SEM order is 5359 Bottom Slice 5360 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5361 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5362 v_blb, {e_bb}, v_brb, 5363 5364 Middle Slice (j) 5365 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5366 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5367 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5368 5369 Top Slice 5370 v_tlf, {e_tf}, v_trf, 5371 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5372 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5373 */ 5374 { 5375 const PetscInt oc = 0; 5376 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5377 const PetscInt oft = ofb + PetscSqr(k-1); 5378 const PetscInt off = oft + PetscSqr(k-1); 5379 const PetscInt ofk = off + PetscSqr(k-1); 5380 const PetscInt ofr = ofk + PetscSqr(k-1); 5381 const PetscInt ofl = ofr + PetscSqr(k-1); 5382 const PetscInt oebl = ofl + PetscSqr(k-1); 5383 const PetscInt oebb = oebl + (k-1); 5384 const PetscInt oebr = oebb + (k-1); 5385 const PetscInt oebf = oebr + (k-1); 5386 const PetscInt oetf = oebf + (k-1); 5387 const PetscInt oetr = oetf + (k-1); 5388 const PetscInt oetb = oetr + (k-1); 5389 const PetscInt oetl = oetb + (k-1); 5390 const PetscInt oerf = oetl + (k-1); 5391 const PetscInt oelf = oerf + (k-1); 5392 const PetscInt oelb = oelf + (k-1); 5393 const PetscInt oerb = oelb + (k-1); 5394 const PetscInt ovblf = oerb + (k-1); 5395 const PetscInt ovblb = ovblf + 1; 5396 const PetscInt ovbrb = ovblb + 1; 5397 const PetscInt ovbrf = ovbrb + 1; 5398 const PetscInt ovtlf = ovbrf + 1; 5399 const PetscInt ovtrf = ovtlf + 1; 5400 const PetscInt ovtrb = ovtrf + 1; 5401 const PetscInt ovtlb = ovtrb + 1; 5402 PetscInt o, n; 5403 5404 /* Bottom Slice */ 5405 /* bottom */ 5406 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5407 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5408 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5409 /* middle */ 5410 for (i = 0; i < k-1; ++i) { 5411 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5412 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;} 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5414 } 5415 /* top */ 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5417 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5419 5420 /* Middle Slice */ 5421 for (j = 0; j < k-1; ++j) { 5422 /* bottom */ 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5424 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; 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5426 /* middle */ 5427 for (i = 0; i < k-1; ++i) { 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5429 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; 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5431 } 5432 /* top */ 5433 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5434 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; 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5436 } 5437 5438 /* Top Slice */ 5439 /* bottom */ 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5441 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5442 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5443 /* middle */ 5444 for (i = 0; i < k-1; ++i) { 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5446 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5448 } 5449 /* top */ 5450 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5451 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5452 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5453 5454 foffset = offset; 5455 } 5456 break; 5457 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5458 } 5459 } 5460 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5461 /* Check permutation */ 5462 { 5463 PetscInt *check; 5464 5465 PetscCall(PetscMalloc1(size, &check)); 5466 for (i = 0; i < size; ++i) { 5467 check[i] = -1; 5468 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5469 } 5470 for (i = 0; i < size; ++i) check[perm[i]] = i; 5471 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5472 PetscCall(PetscFree(check)); 5473 } 5474 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5475 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5476 PetscInt *loc_perm; 5477 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5478 for (PetscInt i=0; i<size; i++) { 5479 loc_perm[i] = perm[i]; 5480 loc_perm[size+i] = size + perm[i]; 5481 } 5482 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5483 } 5484 } 5485 PetscFunctionReturn(0); 5486 } 5487 5488 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5489 { 5490 PetscDS prob; 5491 PetscInt depth, Nf, h; 5492 DMLabel label; 5493 5494 PetscFunctionBeginHot; 5495 PetscCall(DMGetDS(dm, &prob)); 5496 Nf = prob->Nf; 5497 label = dm->depthLabel; 5498 *dspace = NULL; 5499 if (field < Nf) { 5500 PetscObject disc = prob->disc[field]; 5501 5502 if (disc->classid == PETSCFE_CLASSID) { 5503 PetscDualSpace dsp; 5504 5505 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5506 PetscCall(DMLabelGetNumValues(label,&depth)); 5507 PetscCall(DMLabelGetValue(label,point,&h)); 5508 h = depth - 1 - h; 5509 if (h) { 5510 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5511 } else { 5512 *dspace = dsp; 5513 } 5514 } 5515 } 5516 PetscFunctionReturn(0); 5517 } 5518 5519 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5520 { 5521 PetscScalar *array; 5522 const PetscScalar *vArray; 5523 const PetscInt *cone, *coneO; 5524 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5525 5526 PetscFunctionBeginHot; 5527 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5528 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5529 PetscCall(DMPlexGetCone(dm, point, &cone)); 5530 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5531 if (!values || !*values) { 5532 if ((point >= pStart) && (point < pEnd)) { 5533 PetscInt dof; 5534 5535 PetscCall(PetscSectionGetDof(section, point, &dof)); 5536 size += dof; 5537 } 5538 for (p = 0; p < numPoints; ++p) { 5539 const PetscInt cp = cone[p]; 5540 PetscInt dof; 5541 5542 if ((cp < pStart) || (cp >= pEnd)) continue; 5543 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5544 size += dof; 5545 } 5546 if (!values) { 5547 if (csize) *csize = size; 5548 PetscFunctionReturn(0); 5549 } 5550 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5551 } else { 5552 array = *values; 5553 } 5554 size = 0; 5555 PetscCall(VecGetArrayRead(v, &vArray)); 5556 if ((point >= pStart) && (point < pEnd)) { 5557 PetscInt dof, off, d; 5558 const PetscScalar *varr; 5559 5560 PetscCall(PetscSectionGetDof(section, point, &dof)); 5561 PetscCall(PetscSectionGetOffset(section, point, &off)); 5562 varr = &vArray[off]; 5563 for (d = 0; d < dof; ++d, ++offset) { 5564 array[offset] = varr[d]; 5565 } 5566 size += dof; 5567 } 5568 for (p = 0; p < numPoints; ++p) { 5569 const PetscInt cp = cone[p]; 5570 PetscInt o = coneO[p]; 5571 PetscInt dof, off, d; 5572 const PetscScalar *varr; 5573 5574 if ((cp < pStart) || (cp >= pEnd)) continue; 5575 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5576 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5577 varr = &vArray[off]; 5578 if (o >= 0) { 5579 for (d = 0; d < dof; ++d, ++offset) { 5580 array[offset] = varr[d]; 5581 } 5582 } else { 5583 for (d = dof-1; d >= 0; --d, ++offset) { 5584 array[offset] = varr[d]; 5585 } 5586 } 5587 size += dof; 5588 } 5589 PetscCall(VecRestoreArrayRead(v, &vArray)); 5590 if (!*values) { 5591 if (csize) *csize = size; 5592 *values = array; 5593 } else { 5594 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5595 *csize = size; 5596 } 5597 PetscFunctionReturn(0); 5598 } 5599 5600 /* Compress out points not in the section */ 5601 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5602 { 5603 const PetscInt np = *numPoints; 5604 PetscInt pStart, pEnd, p, q; 5605 5606 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5607 for (p = 0, q = 0; p < np; ++p) { 5608 const PetscInt r = points[p*2]; 5609 if ((r >= pStart) && (r < pEnd)) { 5610 points[q*2] = r; 5611 points[q*2+1] = points[p*2+1]; 5612 ++q; 5613 } 5614 } 5615 *numPoints = q; 5616 return 0; 5617 } 5618 5619 /* Compressed closure does not apply closure permutation */ 5620 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5621 { 5622 const PetscInt *cla = NULL; 5623 PetscInt np, *pts = NULL; 5624 5625 PetscFunctionBeginHot; 5626 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5627 if (*clPoints) { 5628 PetscInt dof, off; 5629 5630 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5631 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5632 PetscCall(ISGetIndices(*clPoints, &cla)); 5633 np = dof/2; 5634 pts = (PetscInt *) &cla[off]; 5635 } else { 5636 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5637 PetscCall(CompressPoints_Private(section, &np, pts)); 5638 } 5639 *numPoints = np; 5640 *points = pts; 5641 *clp = cla; 5642 PetscFunctionReturn(0); 5643 } 5644 5645 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5646 { 5647 PetscFunctionBeginHot; 5648 if (!*clPoints) { 5649 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5650 } else { 5651 PetscCall(ISRestoreIndices(*clPoints, clp)); 5652 } 5653 *numPoints = 0; 5654 *points = NULL; 5655 *clSec = NULL; 5656 *clPoints = NULL; 5657 *clp = NULL; 5658 PetscFunctionReturn(0); 5659 } 5660 5661 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5662 { 5663 PetscInt offset = 0, p; 5664 const PetscInt **perms = NULL; 5665 const PetscScalar **flips = NULL; 5666 5667 PetscFunctionBeginHot; 5668 *size = 0; 5669 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5670 for (p = 0; p < numPoints; p++) { 5671 const PetscInt point = points[2*p]; 5672 const PetscInt *perm = perms ? perms[p] : NULL; 5673 const PetscScalar *flip = flips ? flips[p] : NULL; 5674 PetscInt dof, off, d; 5675 const PetscScalar *varr; 5676 5677 PetscCall(PetscSectionGetDof(section, point, &dof)); 5678 PetscCall(PetscSectionGetOffset(section, point, &off)); 5679 varr = &vArray[off]; 5680 if (clperm) { 5681 if (perm) { 5682 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5683 } else { 5684 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5685 } 5686 if (flip) { 5687 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5688 } 5689 } else { 5690 if (perm) { 5691 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5692 } else { 5693 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5694 } 5695 if (flip) { 5696 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5697 } 5698 } 5699 offset += dof; 5700 } 5701 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5702 *size = offset; 5703 PetscFunctionReturn(0); 5704 } 5705 5706 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[]) 5707 { 5708 PetscInt offset = 0, f; 5709 5710 PetscFunctionBeginHot; 5711 *size = 0; 5712 for (f = 0; f < numFields; ++f) { 5713 PetscInt p; 5714 const PetscInt **perms = NULL; 5715 const PetscScalar **flips = NULL; 5716 5717 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5718 for (p = 0; p < numPoints; p++) { 5719 const PetscInt point = points[2*p]; 5720 PetscInt fdof, foff, b; 5721 const PetscScalar *varr; 5722 const PetscInt *perm = perms ? perms[p] : NULL; 5723 const PetscScalar *flip = flips ? flips[p] : NULL; 5724 5725 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5726 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5727 varr = &vArray[foff]; 5728 if (clperm) { 5729 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5730 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5731 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5732 } else { 5733 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5734 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5735 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5736 } 5737 offset += fdof; 5738 } 5739 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5740 } 5741 *size = offset; 5742 PetscFunctionReturn(0); 5743 } 5744 5745 /*@C 5746 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5747 5748 Not collective 5749 5750 Input Parameters: 5751 + dm - The DM 5752 . section - The section describing the layout in v, or NULL to use the default section 5753 . v - The local vector 5754 - point - The point in the DM 5755 5756 Input/Output Parameters: 5757 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5758 - values - An array to use for the values, or NULL to have it allocated automatically; 5759 if the user provided NULL, it is a borrowed array and should not be freed 5760 5761 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5762 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5763 $ assembly function, and a user may already have allocated storage for this operation. 5764 $ 5765 $ A typical use could be 5766 $ 5767 $ values = NULL; 5768 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5769 $ for (cl = 0; cl < clSize; ++cl) { 5770 $ <Compute on closure> 5771 $ } 5772 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5773 $ 5774 $ or 5775 $ 5776 $ PetscMalloc1(clMaxSize, &values); 5777 $ for (p = pStart; p < pEnd; ++p) { 5778 $ clSize = clMaxSize; 5779 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5780 $ for (cl = 0; cl < clSize; ++cl) { 5781 $ <Compute on closure> 5782 $ } 5783 $ } 5784 $ PetscFree(values); 5785 5786 Fortran Notes: 5787 Since it returns an array, this routine is only available in Fortran 90, and you must 5788 include petsc.h90 in your code. 5789 5790 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5791 5792 Level: intermediate 5793 5794 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5795 @*/ 5796 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5797 { 5798 PetscSection clSection; 5799 IS clPoints; 5800 PetscInt *points = NULL; 5801 const PetscInt *clp, *perm; 5802 PetscInt depth, numFields, numPoints, asize; 5803 5804 PetscFunctionBeginHot; 5805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5806 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5807 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5808 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5809 PetscCall(DMPlexGetDepth(dm, &depth)); 5810 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5811 if (depth == 1 && numFields < 2) { 5812 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5813 PetscFunctionReturn(0); 5814 } 5815 /* Get points */ 5816 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5817 /* Get sizes */ 5818 asize = 0; 5819 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5820 PetscInt dof; 5821 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5822 asize += dof; 5823 } 5824 if (values) { 5825 const PetscScalar *vArray; 5826 PetscInt size; 5827 5828 if (*values) { 5829 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); 5830 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5831 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5832 PetscCall(VecGetArrayRead(v, &vArray)); 5833 /* Get values */ 5834 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5835 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5836 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5837 /* Cleanup array */ 5838 PetscCall(VecRestoreArrayRead(v, &vArray)); 5839 } 5840 if (csize) *csize = asize; 5841 /* Cleanup points */ 5842 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5843 PetscFunctionReturn(0); 5844 } 5845 5846 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5847 { 5848 DMLabel depthLabel; 5849 PetscSection clSection; 5850 IS clPoints; 5851 PetscScalar *array; 5852 const PetscScalar *vArray; 5853 PetscInt *points = NULL; 5854 const PetscInt *clp, *perm = NULL; 5855 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5856 5857 PetscFunctionBeginHot; 5858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5859 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5860 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5861 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5862 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5863 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5864 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5865 if (mdepth == 1 && numFields < 2) { 5866 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5867 PetscFunctionReturn(0); 5868 } 5869 /* Get points */ 5870 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5871 for (clsize=0,p=0; p<Np; p++) { 5872 PetscInt dof; 5873 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5874 clsize += dof; 5875 } 5876 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5877 /* Filter points */ 5878 for (p = 0; p < numPoints*2; p += 2) { 5879 PetscInt dep; 5880 5881 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5882 if (dep != depth) continue; 5883 points[Np*2+0] = points[p]; 5884 points[Np*2+1] = points[p+1]; 5885 ++Np; 5886 } 5887 /* Get array */ 5888 if (!values || !*values) { 5889 PetscInt asize = 0, dof; 5890 5891 for (p = 0; p < Np*2; p += 2) { 5892 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5893 asize += dof; 5894 } 5895 if (!values) { 5896 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5897 if (csize) *csize = asize; 5898 PetscFunctionReturn(0); 5899 } 5900 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5901 } else { 5902 array = *values; 5903 } 5904 PetscCall(VecGetArrayRead(v, &vArray)); 5905 /* Get values */ 5906 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5907 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5908 /* Cleanup points */ 5909 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5910 /* Cleanup array */ 5911 PetscCall(VecRestoreArrayRead(v, &vArray)); 5912 if (!*values) { 5913 if (csize) *csize = size; 5914 *values = array; 5915 } else { 5916 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5917 *csize = size; 5918 } 5919 PetscFunctionReturn(0); 5920 } 5921 5922 /*@C 5923 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5924 5925 Not collective 5926 5927 Input Parameters: 5928 + dm - The DM 5929 . section - The section describing the layout in v, or NULL to use the default section 5930 . v - The local vector 5931 . point - The point in the DM 5932 . csize - The number of values in the closure, or NULL 5933 - values - The array of values, which is a borrowed array and should not be freed 5934 5935 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5936 5937 Fortran Notes: 5938 Since it returns an array, this routine is only available in Fortran 90, and you must 5939 include petsc.h90 in your code. 5940 5941 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5942 5943 Level: intermediate 5944 5945 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5946 @*/ 5947 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5948 { 5949 PetscInt size = 0; 5950 5951 PetscFunctionBegin; 5952 /* Should work without recalculating size */ 5953 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5954 *values = NULL; 5955 PetscFunctionReturn(0); 5956 } 5957 5958 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5959 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5960 5961 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[]) 5962 { 5963 PetscInt cdof; /* The number of constraints on this point */ 5964 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5965 PetscScalar *a; 5966 PetscInt off, cind = 0, k; 5967 5968 PetscFunctionBegin; 5969 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5970 PetscCall(PetscSectionGetOffset(section, point, &off)); 5971 a = &array[off]; 5972 if (!cdof || setBC) { 5973 if (clperm) { 5974 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5975 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5976 } else { 5977 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5978 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5979 } 5980 } else { 5981 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5982 if (clperm) { 5983 if (perm) {for (k = 0; k < dof; ++k) { 5984 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5985 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5986 } 5987 } else { 5988 for (k = 0; k < dof; ++k) { 5989 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5990 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5991 } 5992 } 5993 } else { 5994 if (perm) { 5995 for (k = 0; k < dof; ++k) { 5996 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5997 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5998 } 5999 } else { 6000 for (k = 0; k < dof; ++k) { 6001 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6002 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6003 } 6004 } 6005 } 6006 } 6007 PetscFunctionReturn(0); 6008 } 6009 6010 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[]) 6011 { 6012 PetscInt cdof; /* The number of constraints on this point */ 6013 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6014 PetscScalar *a; 6015 PetscInt off, cind = 0, k; 6016 6017 PetscFunctionBegin; 6018 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6019 PetscCall(PetscSectionGetOffset(section, point, &off)); 6020 a = &array[off]; 6021 if (cdof) { 6022 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6023 if (clperm) { 6024 if (perm) { 6025 for (k = 0; k < dof; ++k) { 6026 if ((cind < cdof) && (k == cdofs[cind])) { 6027 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6028 cind++; 6029 } 6030 } 6031 } else { 6032 for (k = 0; k < dof; ++k) { 6033 if ((cind < cdof) && (k == cdofs[cind])) { 6034 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6035 cind++; 6036 } 6037 } 6038 } 6039 } else { 6040 if (perm) { 6041 for (k = 0; k < dof; ++k) { 6042 if ((cind < cdof) && (k == cdofs[cind])) { 6043 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6044 cind++; 6045 } 6046 } 6047 } else { 6048 for (k = 0; k < dof; ++k) { 6049 if ((cind < cdof) && (k == cdofs[cind])) { 6050 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6051 cind++; 6052 } 6053 } 6054 } 6055 } 6056 } 6057 PetscFunctionReturn(0); 6058 } 6059 6060 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[]) 6061 { 6062 PetscScalar *a; 6063 PetscInt fdof, foff, fcdof, foffset = *offset; 6064 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6065 PetscInt cind = 0, b; 6066 6067 PetscFunctionBegin; 6068 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6069 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6070 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6071 a = &array[foff]; 6072 if (!fcdof || setBC) { 6073 if (clperm) { 6074 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6075 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6076 } else { 6077 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6078 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6079 } 6080 } else { 6081 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6082 if (clperm) { 6083 if (perm) { 6084 for (b = 0; b < fdof; b++) { 6085 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6086 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6087 } 6088 } else { 6089 for (b = 0; b < fdof; b++) { 6090 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6091 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6092 } 6093 } 6094 } else { 6095 if (perm) { 6096 for (b = 0; b < fdof; b++) { 6097 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6098 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6099 } 6100 } else { 6101 for (b = 0; b < fdof; b++) { 6102 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6103 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6104 } 6105 } 6106 } 6107 } 6108 *offset += fdof; 6109 PetscFunctionReturn(0); 6110 } 6111 6112 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[]) 6113 { 6114 PetscScalar *a; 6115 PetscInt fdof, foff, fcdof, foffset = *offset; 6116 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6117 PetscInt Nc, cind = 0, ncind = 0, b; 6118 PetscBool ncSet, fcSet; 6119 6120 PetscFunctionBegin; 6121 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6122 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6123 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6124 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6125 a = &array[foff]; 6126 if (fcdof) { 6127 /* We just override fcdof and fcdofs with Ncc and comps */ 6128 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6129 if (clperm) { 6130 if (perm) { 6131 if (comps) { 6132 for (b = 0; b < fdof; b++) { 6133 ncSet = fcSet = PETSC_FALSE; 6134 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6135 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6136 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6137 } 6138 } else { 6139 for (b = 0; b < fdof; b++) { 6140 if ((cind < fcdof) && (b == fcdofs[cind])) { 6141 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6142 ++cind; 6143 } 6144 } 6145 } 6146 } else { 6147 if (comps) { 6148 for (b = 0; b < fdof; b++) { 6149 ncSet = fcSet = PETSC_FALSE; 6150 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6151 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6152 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6153 } 6154 } else { 6155 for (b = 0; b < fdof; b++) { 6156 if ((cind < fcdof) && (b == fcdofs[cind])) { 6157 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6158 ++cind; 6159 } 6160 } 6161 } 6162 } 6163 } else { 6164 if (perm) { 6165 if (comps) { 6166 for (b = 0; b < fdof; b++) { 6167 ncSet = fcSet = PETSC_FALSE; 6168 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6169 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6170 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6171 } 6172 } else { 6173 for (b = 0; b < fdof; b++) { 6174 if ((cind < fcdof) && (b == fcdofs[cind])) { 6175 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6176 ++cind; 6177 } 6178 } 6179 } 6180 } else { 6181 if (comps) { 6182 for (b = 0; b < fdof; b++) { 6183 ncSet = fcSet = PETSC_FALSE; 6184 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6185 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6186 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6187 } 6188 } else { 6189 for (b = 0; b < fdof; b++) { 6190 if ((cind < fcdof) && (b == fcdofs[cind])) { 6191 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6192 ++cind; 6193 } 6194 } 6195 } 6196 } 6197 } 6198 } 6199 *offset += fdof; 6200 PetscFunctionReturn(0); 6201 } 6202 6203 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6204 { 6205 PetscScalar *array; 6206 const PetscInt *cone, *coneO; 6207 PetscInt pStart, pEnd, p, numPoints, off, dof; 6208 6209 PetscFunctionBeginHot; 6210 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6211 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6212 PetscCall(DMPlexGetCone(dm, point, &cone)); 6213 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6214 PetscCall(VecGetArray(v, &array)); 6215 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6216 const PetscInt cp = !p ? point : cone[p-1]; 6217 const PetscInt o = !p ? 0 : coneO[p-1]; 6218 6219 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6220 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6221 /* ADD_VALUES */ 6222 { 6223 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6224 PetscScalar *a; 6225 PetscInt cdof, coff, cind = 0, k; 6226 6227 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6228 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6229 a = &array[coff]; 6230 if (!cdof) { 6231 if (o >= 0) { 6232 for (k = 0; k < dof; ++k) { 6233 a[k] += values[off+k]; 6234 } 6235 } else { 6236 for (k = 0; k < dof; ++k) { 6237 a[k] += values[off+dof-k-1]; 6238 } 6239 } 6240 } else { 6241 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6242 if (o >= 0) { 6243 for (k = 0; k < dof; ++k) { 6244 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6245 a[k] += values[off+k]; 6246 } 6247 } else { 6248 for (k = 0; k < dof; ++k) { 6249 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6250 a[k] += values[off+dof-k-1]; 6251 } 6252 } 6253 } 6254 } 6255 } 6256 PetscCall(VecRestoreArray(v, &array)); 6257 PetscFunctionReturn(0); 6258 } 6259 6260 /*@C 6261 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6262 6263 Not collective 6264 6265 Input Parameters: 6266 + dm - The DM 6267 . section - The section describing the layout in v, or NULL to use the default section 6268 . v - The local vector 6269 . point - The point in the DM 6270 . values - The array of values 6271 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6272 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6273 6274 Fortran Notes: 6275 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6276 6277 Level: intermediate 6278 6279 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6280 @*/ 6281 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6282 { 6283 PetscSection clSection; 6284 IS clPoints; 6285 PetscScalar *array; 6286 PetscInt *points = NULL; 6287 const PetscInt *clp, *clperm = NULL; 6288 PetscInt depth, numFields, numPoints, p, clsize; 6289 6290 PetscFunctionBeginHot; 6291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6292 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6293 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6294 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6295 PetscCall(DMPlexGetDepth(dm, &depth)); 6296 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6297 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6298 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6299 PetscFunctionReturn(0); 6300 } 6301 /* Get points */ 6302 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6303 for (clsize=0,p=0; p<numPoints; p++) { 6304 PetscInt dof; 6305 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6306 clsize += dof; 6307 } 6308 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6309 /* Get array */ 6310 PetscCall(VecGetArray(v, &array)); 6311 /* Get values */ 6312 if (numFields > 0) { 6313 PetscInt offset = 0, f; 6314 for (f = 0; f < numFields; ++f) { 6315 const PetscInt **perms = NULL; 6316 const PetscScalar **flips = NULL; 6317 6318 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6319 switch (mode) { 6320 case INSERT_VALUES: 6321 for (p = 0; p < numPoints; p++) { 6322 const PetscInt point = points[2*p]; 6323 const PetscInt *perm = perms ? perms[p] : NULL; 6324 const PetscScalar *flip = flips ? flips[p] : NULL; 6325 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6326 } break; 6327 case INSERT_ALL_VALUES: 6328 for (p = 0; p < numPoints; p++) { 6329 const PetscInt point = points[2*p]; 6330 const PetscInt *perm = perms ? perms[p] : NULL; 6331 const PetscScalar *flip = flips ? flips[p] : NULL; 6332 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6333 } break; 6334 case INSERT_BC_VALUES: 6335 for (p = 0; p < numPoints; p++) { 6336 const PetscInt point = points[2*p]; 6337 const PetscInt *perm = perms ? perms[p] : NULL; 6338 const PetscScalar *flip = flips ? flips[p] : NULL; 6339 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6340 } break; 6341 case ADD_VALUES: 6342 for (p = 0; p < numPoints; p++) { 6343 const PetscInt point = points[2*p]; 6344 const PetscInt *perm = perms ? perms[p] : NULL; 6345 const PetscScalar *flip = flips ? flips[p] : NULL; 6346 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6347 } break; 6348 case ADD_ALL_VALUES: 6349 for (p = 0; p < numPoints; p++) { 6350 const PetscInt point = points[2*p]; 6351 const PetscInt *perm = perms ? perms[p] : NULL; 6352 const PetscScalar *flip = flips ? flips[p] : NULL; 6353 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6354 } break; 6355 case ADD_BC_VALUES: 6356 for (p = 0; p < numPoints; p++) { 6357 const PetscInt point = points[2*p]; 6358 const PetscInt *perm = perms ? perms[p] : NULL; 6359 const PetscScalar *flip = flips ? flips[p] : NULL; 6360 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6361 } break; 6362 default: 6363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6364 } 6365 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6366 } 6367 } else { 6368 PetscInt dof, off; 6369 const PetscInt **perms = NULL; 6370 const PetscScalar **flips = NULL; 6371 6372 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6373 switch (mode) { 6374 case INSERT_VALUES: 6375 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6376 const PetscInt point = points[2*p]; 6377 const PetscInt *perm = perms ? perms[p] : NULL; 6378 const PetscScalar *flip = flips ? flips[p] : NULL; 6379 PetscCall(PetscSectionGetDof(section, point, &dof)); 6380 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6381 } break; 6382 case INSERT_ALL_VALUES: 6383 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6384 const PetscInt point = points[2*p]; 6385 const PetscInt *perm = perms ? perms[p] : NULL; 6386 const PetscScalar *flip = flips ? flips[p] : NULL; 6387 PetscCall(PetscSectionGetDof(section, point, &dof)); 6388 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6389 } break; 6390 case INSERT_BC_VALUES: 6391 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6392 const PetscInt point = points[2*p]; 6393 const PetscInt *perm = perms ? perms[p] : NULL; 6394 const PetscScalar *flip = flips ? flips[p] : NULL; 6395 PetscCall(PetscSectionGetDof(section, point, &dof)); 6396 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6397 } break; 6398 case ADD_VALUES: 6399 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6400 const PetscInt point = points[2*p]; 6401 const PetscInt *perm = perms ? perms[p] : NULL; 6402 const PetscScalar *flip = flips ? flips[p] : NULL; 6403 PetscCall(PetscSectionGetDof(section, point, &dof)); 6404 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6405 } break; 6406 case ADD_ALL_VALUES: 6407 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6408 const PetscInt point = points[2*p]; 6409 const PetscInt *perm = perms ? perms[p] : NULL; 6410 const PetscScalar *flip = flips ? flips[p] : NULL; 6411 PetscCall(PetscSectionGetDof(section, point, &dof)); 6412 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6413 } break; 6414 case ADD_BC_VALUES: 6415 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6416 const PetscInt point = points[2*p]; 6417 const PetscInt *perm = perms ? perms[p] : NULL; 6418 const PetscScalar *flip = flips ? flips[p] : NULL; 6419 PetscCall(PetscSectionGetDof(section, point, &dof)); 6420 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6421 } break; 6422 default: 6423 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6424 } 6425 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6426 } 6427 /* Cleanup points */ 6428 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6429 /* Cleanup array */ 6430 PetscCall(VecRestoreArray(v, &array)); 6431 PetscFunctionReturn(0); 6432 } 6433 6434 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6435 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6436 { 6437 PetscFunctionBegin; 6438 if (label) { 6439 PetscBool contains; 6440 PetscInt fdof; 6441 6442 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6443 if (!contains) { 6444 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6445 *offset += fdof; 6446 PetscFunctionReturn(1); 6447 } 6448 } 6449 PetscFunctionReturn(0); 6450 } 6451 6452 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6453 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) 6454 { 6455 PetscSection clSection; 6456 IS clPoints; 6457 PetscScalar *array; 6458 PetscInt *points = NULL; 6459 const PetscInt *clp; 6460 PetscInt numFields, numPoints, p; 6461 PetscInt offset = 0, f; 6462 6463 PetscFunctionBeginHot; 6464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6465 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6466 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6467 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6468 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6469 /* Get points */ 6470 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6471 /* Get array */ 6472 PetscCall(VecGetArray(v, &array)); 6473 /* Get values */ 6474 for (f = 0; f < numFields; ++f) { 6475 const PetscInt **perms = NULL; 6476 const PetscScalar **flips = NULL; 6477 6478 if (!fieldActive[f]) { 6479 for (p = 0; p < numPoints*2; p += 2) { 6480 PetscInt fdof; 6481 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6482 offset += fdof; 6483 } 6484 continue; 6485 } 6486 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6487 switch (mode) { 6488 case INSERT_VALUES: 6489 for (p = 0; p < numPoints; p++) { 6490 const PetscInt point = points[2*p]; 6491 const PetscInt *perm = perms ? perms[p] : NULL; 6492 const PetscScalar *flip = flips ? flips[p] : NULL; 6493 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6494 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6495 } break; 6496 case INSERT_ALL_VALUES: 6497 for (p = 0; p < numPoints; p++) { 6498 const PetscInt point = points[2*p]; 6499 const PetscInt *perm = perms ? perms[p] : NULL; 6500 const PetscScalar *flip = flips ? flips[p] : NULL; 6501 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6502 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6503 } break; 6504 case INSERT_BC_VALUES: 6505 for (p = 0; p < numPoints; p++) { 6506 const PetscInt point = points[2*p]; 6507 const PetscInt *perm = perms ? perms[p] : NULL; 6508 const PetscScalar *flip = flips ? flips[p] : NULL; 6509 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6510 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6511 } break; 6512 case ADD_VALUES: 6513 for (p = 0; p < numPoints; p++) { 6514 const PetscInt point = points[2*p]; 6515 const PetscInt *perm = perms ? perms[p] : NULL; 6516 const PetscScalar *flip = flips ? flips[p] : NULL; 6517 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6518 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6519 } break; 6520 case ADD_ALL_VALUES: 6521 for (p = 0; p < numPoints; p++) { 6522 const PetscInt point = points[2*p]; 6523 const PetscInt *perm = perms ? perms[p] : NULL; 6524 const PetscScalar *flip = flips ? flips[p] : NULL; 6525 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6526 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6527 } break; 6528 default: 6529 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6530 } 6531 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6532 } 6533 /* Cleanup points */ 6534 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6535 /* Cleanup array */ 6536 PetscCall(VecRestoreArray(v, &array)); 6537 PetscFunctionReturn(0); 6538 } 6539 6540 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6541 { 6542 PetscMPIInt rank; 6543 PetscInt i, j; 6544 6545 PetscFunctionBegin; 6546 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6547 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6548 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6549 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6550 numCIndices = numCIndices ? numCIndices : numRIndices; 6551 if (!values) PetscFunctionReturn(0); 6552 for (i = 0; i < numRIndices; i++) { 6553 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6554 for (j = 0; j < numCIndices; j++) { 6555 #if defined(PETSC_USE_COMPLEX) 6556 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6557 #else 6558 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6559 #endif 6560 } 6561 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6562 } 6563 PetscFunctionReturn(0); 6564 } 6565 6566 /* 6567 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6568 6569 Input Parameters: 6570 + section - The section for this data layout 6571 . islocal - Is the section (and thus indices being requested) local or global? 6572 . point - The point contributing dofs with these indices 6573 . off - The global offset of this point 6574 . loff - The local offset of each field 6575 . setBC - The flag determining whether to include indices of boundary values 6576 . perm - A permutation of the dofs on this point, or NULL 6577 - indperm - A permutation of the entire indices array, or NULL 6578 6579 Output Parameter: 6580 . indices - Indices for dofs on this point 6581 6582 Level: developer 6583 6584 Note: The indices could be local or global, depending on the value of 'off'. 6585 */ 6586 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6587 { 6588 PetscInt dof; /* The number of unknowns on this point */ 6589 PetscInt cdof; /* The number of constraints on this point */ 6590 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6591 PetscInt cind = 0, k; 6592 6593 PetscFunctionBegin; 6594 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6595 PetscCall(PetscSectionGetDof(section, point, &dof)); 6596 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6597 if (!cdof || setBC) { 6598 for (k = 0; k < dof; ++k) { 6599 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6600 const PetscInt ind = indperm ? indperm[preind] : preind; 6601 6602 indices[ind] = off + k; 6603 } 6604 } else { 6605 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6606 for (k = 0; k < dof; ++k) { 6607 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6608 const PetscInt ind = indperm ? indperm[preind] : preind; 6609 6610 if ((cind < cdof) && (k == cdofs[cind])) { 6611 /* Insert check for returning constrained indices */ 6612 indices[ind] = -(off+k+1); 6613 ++cind; 6614 } else { 6615 indices[ind] = off + k - (islocal ? 0 : cind); 6616 } 6617 } 6618 } 6619 *loff += dof; 6620 PetscFunctionReturn(0); 6621 } 6622 6623 /* 6624 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6625 6626 Input Parameters: 6627 + section - a section (global or local) 6628 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6629 . point - point within section 6630 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6631 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6632 . setBC - identify constrained (boundary condition) points via involution. 6633 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6634 . permsoff - offset 6635 - indperm - index permutation 6636 6637 Output Parameter: 6638 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6639 . indices - array to hold indices (as defined by section) of each dof associated with point 6640 6641 Notes: 6642 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6643 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6644 in the local vector. 6645 6646 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6647 significant). It is invalid to call with a global section and setBC=true. 6648 6649 Developer Note: 6650 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6651 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6652 offset could be obtained from the section instead of passing it explicitly as we do now. 6653 6654 Example: 6655 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6656 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6657 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6658 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. 6659 6660 Level: developer 6661 */ 6662 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[]) 6663 { 6664 PetscInt numFields, foff, f; 6665 6666 PetscFunctionBegin; 6667 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6668 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6669 for (f = 0, foff = 0; f < numFields; ++f) { 6670 PetscInt fdof, cfdof; 6671 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6672 PetscInt cind = 0, b; 6673 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6674 6675 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6676 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6677 if (!cfdof || setBC) { 6678 for (b = 0; b < fdof; ++b) { 6679 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6680 const PetscInt ind = indperm ? indperm[preind] : preind; 6681 6682 indices[ind] = off+foff+b; 6683 } 6684 } else { 6685 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6686 for (b = 0; b < fdof; ++b) { 6687 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6688 const PetscInt ind = indperm ? indperm[preind] : preind; 6689 6690 if ((cind < cfdof) && (b == fcdofs[cind])) { 6691 indices[ind] = -(off+foff+b+1); 6692 ++cind; 6693 } else { 6694 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6695 } 6696 } 6697 } 6698 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6699 foffs[f] += fdof; 6700 } 6701 PetscFunctionReturn(0); 6702 } 6703 6704 /* 6705 This version believes the globalSection offsets for each field, rather than just the point offset 6706 6707 . foffs - The offset into 'indices' for each field, since it is segregated by field 6708 6709 Notes: 6710 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6711 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6712 */ 6713 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6714 { 6715 PetscInt numFields, foff, f; 6716 6717 PetscFunctionBegin; 6718 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6719 for (f = 0; f < numFields; ++f) { 6720 PetscInt fdof, cfdof; 6721 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6722 PetscInt cind = 0, b; 6723 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6724 6725 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6726 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6727 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6728 if (!cfdof) { 6729 for (b = 0; b < fdof; ++b) { 6730 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6731 const PetscInt ind = indperm ? indperm[preind] : preind; 6732 6733 indices[ind] = foff+b; 6734 } 6735 } else { 6736 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6737 for (b = 0; b < fdof; ++b) { 6738 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6739 const PetscInt ind = indperm ? indperm[preind] : preind; 6740 6741 if ((cind < cfdof) && (b == fcdofs[cind])) { 6742 indices[ind] = -(foff+b+1); 6743 ++cind; 6744 } else { 6745 indices[ind] = foff+b-cind; 6746 } 6747 } 6748 } 6749 foffs[f] += fdof; 6750 } 6751 PetscFunctionReturn(0); 6752 } 6753 6754 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) 6755 { 6756 Mat cMat; 6757 PetscSection aSec, cSec; 6758 IS aIS; 6759 PetscInt aStart = -1, aEnd = -1; 6760 const PetscInt *anchors; 6761 PetscInt numFields, f, p, q, newP = 0; 6762 PetscInt newNumPoints = 0, newNumIndices = 0; 6763 PetscInt *newPoints, *indices, *newIndices; 6764 PetscInt maxAnchor, maxDof; 6765 PetscInt newOffsets[32]; 6766 PetscInt *pointMatOffsets[32]; 6767 PetscInt *newPointOffsets[32]; 6768 PetscScalar *pointMat[32]; 6769 PetscScalar *newValues=NULL,*tmpValues; 6770 PetscBool anyConstrained = PETSC_FALSE; 6771 6772 PetscFunctionBegin; 6773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6774 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6775 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6776 6777 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6778 /* if there are point-to-point constraints */ 6779 if (aSec) { 6780 PetscCall(PetscArrayzero(newOffsets, 32)); 6781 PetscCall(ISGetIndices(aIS,&anchors)); 6782 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6783 /* figure out how many points are going to be in the new element matrix 6784 * (we allow double counting, because it's all just going to be summed 6785 * into the global matrix anyway) */ 6786 for (p = 0; p < 2*numPoints; p+=2) { 6787 PetscInt b = points[p]; 6788 PetscInt bDof = 0, bSecDof; 6789 6790 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6791 if (!bSecDof) { 6792 continue; 6793 } 6794 if (b >= aStart && b < aEnd) { 6795 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6796 } 6797 if (bDof) { 6798 /* this point is constrained */ 6799 /* it is going to be replaced by its anchors */ 6800 PetscInt bOff, q; 6801 6802 anyConstrained = PETSC_TRUE; 6803 newNumPoints += bDof; 6804 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6805 for (q = 0; q < bDof; q++) { 6806 PetscInt a = anchors[bOff + q]; 6807 PetscInt aDof; 6808 6809 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6810 newNumIndices += aDof; 6811 for (f = 0; f < numFields; ++f) { 6812 PetscInt fDof; 6813 6814 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6815 newOffsets[f+1] += fDof; 6816 } 6817 } 6818 } 6819 else { 6820 /* this point is not constrained */ 6821 newNumPoints++; 6822 newNumIndices += bSecDof; 6823 for (f = 0; f < numFields; ++f) { 6824 PetscInt fDof; 6825 6826 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6827 newOffsets[f+1] += fDof; 6828 } 6829 } 6830 } 6831 } 6832 if (!anyConstrained) { 6833 if (outNumPoints) *outNumPoints = 0; 6834 if (outNumIndices) *outNumIndices = 0; 6835 if (outPoints) *outPoints = NULL; 6836 if (outValues) *outValues = NULL; 6837 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6838 PetscFunctionReturn(0); 6839 } 6840 6841 if (outNumPoints) *outNumPoints = newNumPoints; 6842 if (outNumIndices) *outNumIndices = newNumIndices; 6843 6844 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6845 6846 if (!outPoints && !outValues) { 6847 if (offsets) { 6848 for (f = 0; f <= numFields; f++) { 6849 offsets[f] = newOffsets[f]; 6850 } 6851 } 6852 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6853 PetscFunctionReturn(0); 6854 } 6855 6856 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6857 6858 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6859 6860 /* workspaces */ 6861 if (numFields) { 6862 for (f = 0; f < numFields; f++) { 6863 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6864 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6865 } 6866 } 6867 else { 6868 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6869 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6870 } 6871 6872 /* get workspaces for the point-to-point matrices */ 6873 if (numFields) { 6874 PetscInt totalOffset, totalMatOffset; 6875 6876 for (p = 0; p < numPoints; p++) { 6877 PetscInt b = points[2*p]; 6878 PetscInt bDof = 0, bSecDof; 6879 6880 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6881 if (!bSecDof) { 6882 for (f = 0; f < numFields; f++) { 6883 newPointOffsets[f][p + 1] = 0; 6884 pointMatOffsets[f][p + 1] = 0; 6885 } 6886 continue; 6887 } 6888 if (b >= aStart && b < aEnd) { 6889 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6890 } 6891 if (bDof) { 6892 for (f = 0; f < numFields; f++) { 6893 PetscInt fDof, q, bOff, allFDof = 0; 6894 6895 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6896 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6897 for (q = 0; q < bDof; q++) { 6898 PetscInt a = anchors[bOff + q]; 6899 PetscInt aFDof; 6900 6901 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6902 allFDof += aFDof; 6903 } 6904 newPointOffsets[f][p+1] = allFDof; 6905 pointMatOffsets[f][p+1] = fDof * allFDof; 6906 } 6907 } 6908 else { 6909 for (f = 0; f < numFields; f++) { 6910 PetscInt fDof; 6911 6912 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6913 newPointOffsets[f][p+1] = fDof; 6914 pointMatOffsets[f][p+1] = 0; 6915 } 6916 } 6917 } 6918 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6919 newPointOffsets[f][0] = totalOffset; 6920 pointMatOffsets[f][0] = totalMatOffset; 6921 for (p = 0; p < numPoints; p++) { 6922 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6923 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6924 } 6925 totalOffset = newPointOffsets[f][numPoints]; 6926 totalMatOffset = pointMatOffsets[f][numPoints]; 6927 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6928 } 6929 } 6930 else { 6931 for (p = 0; p < numPoints; p++) { 6932 PetscInt b = points[2*p]; 6933 PetscInt bDof = 0, bSecDof; 6934 6935 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6936 if (!bSecDof) { 6937 newPointOffsets[0][p + 1] = 0; 6938 pointMatOffsets[0][p + 1] = 0; 6939 continue; 6940 } 6941 if (b >= aStart && b < aEnd) { 6942 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6943 } 6944 if (bDof) { 6945 PetscInt bOff, q, allDof = 0; 6946 6947 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6948 for (q = 0; q < bDof; q++) { 6949 PetscInt a = anchors[bOff + q], aDof; 6950 6951 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6952 allDof += aDof; 6953 } 6954 newPointOffsets[0][p+1] = allDof; 6955 pointMatOffsets[0][p+1] = bSecDof * allDof; 6956 } 6957 else { 6958 newPointOffsets[0][p+1] = bSecDof; 6959 pointMatOffsets[0][p+1] = 0; 6960 } 6961 } 6962 newPointOffsets[0][0] = 0; 6963 pointMatOffsets[0][0] = 0; 6964 for (p = 0; p < numPoints; p++) { 6965 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6966 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6967 } 6968 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6969 } 6970 6971 /* output arrays */ 6972 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6973 6974 /* get the point-to-point matrices; construct newPoints */ 6975 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6976 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6977 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6978 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6979 if (numFields) { 6980 for (p = 0, newP = 0; p < numPoints; p++) { 6981 PetscInt b = points[2*p]; 6982 PetscInt o = points[2*p+1]; 6983 PetscInt bDof = 0, bSecDof; 6984 6985 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6986 if (!bSecDof) { 6987 continue; 6988 } 6989 if (b >= aStart && b < aEnd) { 6990 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6991 } 6992 if (bDof) { 6993 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6994 6995 fStart[0] = 0; 6996 fEnd[0] = 0; 6997 for (f = 0; f < numFields; f++) { 6998 PetscInt fDof; 6999 7000 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7001 fStart[f+1] = fStart[f] + fDof; 7002 fEnd[f+1] = fStart[f+1]; 7003 } 7004 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7005 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7006 7007 fAnchorStart[0] = 0; 7008 fAnchorEnd[0] = 0; 7009 for (f = 0; f < numFields; f++) { 7010 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7011 7012 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7013 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7014 } 7015 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7016 for (q = 0; q < bDof; q++) { 7017 PetscInt a = anchors[bOff + q], aOff; 7018 7019 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7020 newPoints[2*(newP + q)] = a; 7021 newPoints[2*(newP + q) + 1] = 0; 7022 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7023 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7024 } 7025 newP += bDof; 7026 7027 if (outValues) { 7028 /* get the point-to-point submatrix */ 7029 for (f = 0; f < numFields; f++) { 7030 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7031 } 7032 } 7033 } 7034 else { 7035 newPoints[2 * newP] = b; 7036 newPoints[2 * newP + 1] = o; 7037 newP++; 7038 } 7039 } 7040 } else { 7041 for (p = 0; p < numPoints; p++) { 7042 PetscInt b = points[2*p]; 7043 PetscInt o = points[2*p+1]; 7044 PetscInt bDof = 0, bSecDof; 7045 7046 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7047 if (!bSecDof) { 7048 continue; 7049 } 7050 if (b >= aStart && b < aEnd) { 7051 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7052 } 7053 if (bDof) { 7054 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7055 7056 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7057 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7058 7059 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7060 for (q = 0; q < bDof; q++) { 7061 PetscInt a = anchors[bOff + q], aOff; 7062 7063 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7064 7065 newPoints[2*(newP + q)] = a; 7066 newPoints[2*(newP + q) + 1] = 0; 7067 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7068 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7069 } 7070 newP += bDof; 7071 7072 /* get the point-to-point submatrix */ 7073 if (outValues) { 7074 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7075 } 7076 } 7077 else { 7078 newPoints[2 * newP] = b; 7079 newPoints[2 * newP + 1] = o; 7080 newP++; 7081 } 7082 } 7083 } 7084 7085 if (outValues) { 7086 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7087 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7088 /* multiply constraints on the right */ 7089 if (numFields) { 7090 for (f = 0; f < numFields; f++) { 7091 PetscInt oldOff = offsets[f]; 7092 7093 for (p = 0; p < numPoints; p++) { 7094 PetscInt cStart = newPointOffsets[f][p]; 7095 PetscInt b = points[2 * p]; 7096 PetscInt c, r, k; 7097 PetscInt dof; 7098 7099 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7100 if (!dof) { 7101 continue; 7102 } 7103 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7104 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7105 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7106 7107 for (r = 0; r < numIndices; r++) { 7108 for (c = 0; c < nCols; c++) { 7109 for (k = 0; k < dof; k++) { 7110 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7111 } 7112 } 7113 } 7114 } 7115 else { 7116 /* copy this column as is */ 7117 for (r = 0; r < numIndices; r++) { 7118 for (c = 0; c < dof; c++) { 7119 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7120 } 7121 } 7122 } 7123 oldOff += dof; 7124 } 7125 } 7126 } 7127 else { 7128 PetscInt oldOff = 0; 7129 for (p = 0; p < numPoints; p++) { 7130 PetscInt cStart = newPointOffsets[0][p]; 7131 PetscInt b = points[2 * p]; 7132 PetscInt c, r, k; 7133 PetscInt dof; 7134 7135 PetscCall(PetscSectionGetDof(section,b,&dof)); 7136 if (!dof) { 7137 continue; 7138 } 7139 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7140 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7141 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7142 7143 for (r = 0; r < numIndices; r++) { 7144 for (c = 0; c < nCols; c++) { 7145 for (k = 0; k < dof; k++) { 7146 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7147 } 7148 } 7149 } 7150 } 7151 else { 7152 /* copy this column as is */ 7153 for (r = 0; r < numIndices; r++) { 7154 for (c = 0; c < dof; c++) { 7155 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7156 } 7157 } 7158 } 7159 oldOff += dof; 7160 } 7161 } 7162 7163 if (multiplyLeft) { 7164 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7165 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7166 /* multiply constraints transpose on the left */ 7167 if (numFields) { 7168 for (f = 0; f < numFields; f++) { 7169 PetscInt oldOff = offsets[f]; 7170 7171 for (p = 0; p < numPoints; p++) { 7172 PetscInt rStart = newPointOffsets[f][p]; 7173 PetscInt b = points[2 * p]; 7174 PetscInt c, r, k; 7175 PetscInt dof; 7176 7177 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7178 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7179 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7180 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7181 7182 for (r = 0; r < nRows; r++) { 7183 for (c = 0; c < newNumIndices; c++) { 7184 for (k = 0; k < dof; k++) { 7185 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7186 } 7187 } 7188 } 7189 } 7190 else { 7191 /* copy this row as is */ 7192 for (r = 0; r < dof; r++) { 7193 for (c = 0; c < newNumIndices; c++) { 7194 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7195 } 7196 } 7197 } 7198 oldOff += dof; 7199 } 7200 } 7201 } 7202 else { 7203 PetscInt oldOff = 0; 7204 7205 for (p = 0; p < numPoints; p++) { 7206 PetscInt rStart = newPointOffsets[0][p]; 7207 PetscInt b = points[2 * p]; 7208 PetscInt c, r, k; 7209 PetscInt dof; 7210 7211 PetscCall(PetscSectionGetDof(section,b,&dof)); 7212 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7213 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7214 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7215 7216 for (r = 0; r < nRows; r++) { 7217 for (c = 0; c < newNumIndices; c++) { 7218 for (k = 0; k < dof; k++) { 7219 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7220 } 7221 } 7222 } 7223 } 7224 else { 7225 /* copy this row as is */ 7226 for (r = 0; r < dof; r++) { 7227 for (c = 0; c < newNumIndices; c++) { 7228 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7229 } 7230 } 7231 } 7232 oldOff += dof; 7233 } 7234 } 7235 7236 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7237 } 7238 else { 7239 newValues = tmpValues; 7240 } 7241 } 7242 7243 /* clean up */ 7244 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7245 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7246 7247 if (numFields) { 7248 for (f = 0; f < numFields; f++) { 7249 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7250 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7251 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7252 } 7253 } 7254 else { 7255 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7256 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7257 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7258 } 7259 PetscCall(ISRestoreIndices(aIS,&anchors)); 7260 7261 /* output */ 7262 if (outPoints) { 7263 *outPoints = newPoints; 7264 } 7265 else { 7266 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7267 } 7268 if (outValues) { 7269 *outValues = newValues; 7270 } 7271 for (f = 0; f <= numFields; f++) { 7272 offsets[f] = newOffsets[f]; 7273 } 7274 PetscFunctionReturn(0); 7275 } 7276 7277 /*@C 7278 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7279 7280 Not collective 7281 7282 Input Parameters: 7283 + dm - The DM 7284 . section - The PetscSection describing the points (a local section) 7285 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7286 . point - The point defining the closure 7287 - useClPerm - Use the closure point permutation if available 7288 7289 Output Parameters: 7290 + numIndices - The number of dof indices in the closure of point with the input sections 7291 . indices - The dof indices 7292 . outOffsets - Array to write the field offsets into, or NULL 7293 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7294 7295 Notes: 7296 Must call DMPlexRestoreClosureIndices() to free allocated memory 7297 7298 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7299 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7300 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7301 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7302 indices (with the above semantics) are implied. 7303 7304 Level: advanced 7305 7306 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7307 @*/ 7308 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7309 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7310 { 7311 /* Closure ordering */ 7312 PetscSection clSection; 7313 IS clPoints; 7314 const PetscInt *clp; 7315 PetscInt *points; 7316 const PetscInt *clperm = NULL; 7317 /* Dof permutation and sign flips */ 7318 const PetscInt **perms[32] = {NULL}; 7319 const PetscScalar **flips[32] = {NULL}; 7320 PetscScalar *valCopy = NULL; 7321 /* Hanging node constraints */ 7322 PetscInt *pointsC = NULL; 7323 PetscScalar *valuesC = NULL; 7324 PetscInt NclC, NiC; 7325 7326 PetscInt *idx; 7327 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7328 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7329 7330 PetscFunctionBeginHot; 7331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7332 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7333 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7334 if (numIndices) PetscValidIntPointer(numIndices, 6); 7335 if (indices) PetscValidPointer(indices, 7); 7336 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7337 if (values) PetscValidPointer(values, 9); 7338 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7339 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7340 PetscCall(PetscArrayzero(offsets, 32)); 7341 /* 1) Get points in closure */ 7342 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7343 if (useClPerm) { 7344 PetscInt depth, clsize; 7345 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7346 for (clsize=0,p=0; p<Ncl; p++) { 7347 PetscInt dof; 7348 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7349 clsize += dof; 7350 } 7351 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7352 } 7353 /* 2) Get number of indices on these points and field offsets from section */ 7354 for (p = 0; p < Ncl*2; p += 2) { 7355 PetscInt dof, fdof; 7356 7357 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7358 for (f = 0; f < Nf; ++f) { 7359 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7360 offsets[f+1] += fdof; 7361 } 7362 Ni += dof; 7363 } 7364 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7365 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7366 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7367 for (f = 0; f < PetscMax(1, Nf); ++f) { 7368 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7369 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7370 /* may need to apply sign changes to the element matrix */ 7371 if (values && flips[f]) { 7372 PetscInt foffset = offsets[f]; 7373 7374 for (p = 0; p < Ncl; ++p) { 7375 PetscInt pnt = points[2*p], fdof; 7376 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7377 7378 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7379 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7380 if (flip) { 7381 PetscInt i, j, k; 7382 7383 if (!valCopy) { 7384 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7385 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7386 *values = valCopy; 7387 } 7388 for (i = 0; i < fdof; ++i) { 7389 PetscScalar fval = flip[i]; 7390 7391 for (k = 0; k < Ni; ++k) { 7392 valCopy[Ni * (foffset + i) + k] *= fval; 7393 valCopy[Ni * k + (foffset + i)] *= fval; 7394 } 7395 } 7396 } 7397 foffset += fdof; 7398 } 7399 } 7400 } 7401 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7402 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7403 if (NclC) { 7404 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7405 for (f = 0; f < PetscMax(1, Nf); ++f) { 7406 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7407 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7408 } 7409 for (f = 0; f < PetscMax(1, Nf); ++f) { 7410 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7411 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7412 } 7413 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7414 Ncl = NclC; 7415 Ni = NiC; 7416 points = pointsC; 7417 if (values) *values = valuesC; 7418 } 7419 /* 5) Calculate indices */ 7420 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7421 if (Nf) { 7422 PetscInt idxOff; 7423 PetscBool useFieldOffsets; 7424 7425 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7426 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7427 if (useFieldOffsets) { 7428 for (p = 0; p < Ncl; ++p) { 7429 const PetscInt pnt = points[p*2]; 7430 7431 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7432 } 7433 } else { 7434 for (p = 0; p < Ncl; ++p) { 7435 const PetscInt pnt = points[p*2]; 7436 7437 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7438 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7439 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7440 * global section. */ 7441 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7442 } 7443 } 7444 } else { 7445 PetscInt off = 0, idxOff; 7446 7447 for (p = 0; p < Ncl; ++p) { 7448 const PetscInt pnt = points[p*2]; 7449 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7450 7451 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7452 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7453 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7454 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7455 } 7456 } 7457 /* 6) Cleanup */ 7458 for (f = 0; f < PetscMax(1, Nf); ++f) { 7459 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7460 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7461 } 7462 if (NclC) { 7463 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7464 } else { 7465 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7466 } 7467 7468 if (numIndices) *numIndices = Ni; 7469 if (indices) *indices = idx; 7470 PetscFunctionReturn(0); 7471 } 7472 7473 /*@C 7474 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7475 7476 Not collective 7477 7478 Input Parameters: 7479 + dm - The DM 7480 . section - The PetscSection describing the points (a local section) 7481 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7482 . point - The point defining the closure 7483 - useClPerm - Use the closure point permutation if available 7484 7485 Output Parameters: 7486 + numIndices - The number of dof indices in the closure of point with the input sections 7487 . indices - The dof indices 7488 . outOffsets - Array to write the field offsets into, or NULL 7489 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7490 7491 Notes: 7492 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7493 7494 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7495 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7496 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7497 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7498 indices (with the above semantics) are implied. 7499 7500 Level: advanced 7501 7502 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7503 @*/ 7504 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7505 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7506 { 7507 PetscFunctionBegin; 7508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7509 PetscValidPointer(indices, 7); 7510 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7511 PetscFunctionReturn(0); 7512 } 7513 7514 /*@C 7515 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7516 7517 Not collective 7518 7519 Input Parameters: 7520 + dm - The DM 7521 . section - The section describing the layout in v, or NULL to use the default section 7522 . globalSection - The section describing the layout in v, or NULL to use the default global section 7523 . A - The matrix 7524 . point - The point in the DM 7525 . values - The array of values 7526 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7527 7528 Fortran Notes: 7529 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7530 7531 Level: intermediate 7532 7533 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7534 @*/ 7535 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7536 { 7537 DM_Plex *mesh = (DM_Plex*) dm->data; 7538 PetscInt *indices; 7539 PetscInt numIndices; 7540 const PetscScalar *valuesOrig = values; 7541 PetscErrorCode ierr; 7542 7543 PetscFunctionBegin; 7544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7545 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7546 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7547 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7548 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7549 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7550 7551 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7552 7553 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7554 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7555 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7556 if (ierr) { 7557 PetscMPIInt rank; 7558 7559 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7560 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7561 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7562 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7563 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7564 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7565 } 7566 if (mesh->printFEM > 1) { 7567 PetscInt i; 7568 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7569 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7570 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7571 } 7572 7573 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7574 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7575 PetscFunctionReturn(0); 7576 } 7577 7578 /*@C 7579 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7580 7581 Not collective 7582 7583 Input Parameters: 7584 + dmRow - The DM for the row fields 7585 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7586 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7587 . dmCol - The DM for the column fields 7588 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7589 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7590 . A - The matrix 7591 . point - The point in the DMs 7592 . values - The array of values 7593 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7594 7595 Level: intermediate 7596 7597 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7598 @*/ 7599 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7600 { 7601 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7602 PetscInt *indicesRow, *indicesCol; 7603 PetscInt numIndicesRow, numIndicesCol; 7604 const PetscScalar *valuesOrig = values; 7605 PetscErrorCode ierr; 7606 7607 PetscFunctionBegin; 7608 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7609 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7610 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7611 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7612 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7613 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7614 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7615 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7616 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7617 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7618 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7619 7620 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7621 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7622 7623 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7624 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7625 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7626 if (ierr) { 7627 PetscMPIInt rank; 7628 7629 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7630 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7631 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7632 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7633 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7634 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7635 } 7636 7637 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7638 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7639 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7640 PetscFunctionReturn(0); 7641 } 7642 7643 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7644 { 7645 DM_Plex *mesh = (DM_Plex*) dmf->data; 7646 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7647 PetscInt *cpoints = NULL; 7648 PetscInt *findices, *cindices; 7649 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7650 PetscInt foffsets[32], coffsets[32]; 7651 DMPolytopeType ct; 7652 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7653 PetscErrorCode ierr; 7654 7655 PetscFunctionBegin; 7656 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7657 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7658 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7659 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7660 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7661 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7662 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7663 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7664 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7665 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7666 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7667 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7668 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7669 PetscCall(PetscArrayzero(foffsets, 32)); 7670 PetscCall(PetscArrayzero(coffsets, 32)); 7671 /* Column indices */ 7672 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7673 maxFPoints = numCPoints; 7674 /* Compress out points not in the section */ 7675 /* TODO: Squeeze out points with 0 dof as well */ 7676 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7677 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7678 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7679 cpoints[q*2] = cpoints[p]; 7680 cpoints[q*2+1] = cpoints[p+1]; 7681 ++q; 7682 } 7683 } 7684 numCPoints = q; 7685 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7686 PetscInt fdof; 7687 7688 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7689 if (!dof) continue; 7690 for (f = 0; f < numFields; ++f) { 7691 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7692 coffsets[f+1] += fdof; 7693 } 7694 numCIndices += dof; 7695 } 7696 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7697 /* Row indices */ 7698 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7699 { 7700 DMPlexTransform tr; 7701 DMPolytopeType *rct; 7702 PetscInt *rsize, *rcone, *rornt, Nt; 7703 7704 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7705 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7706 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7707 numSubcells = rsize[Nt-1]; 7708 PetscCall(DMPlexTransformDestroy(&tr)); 7709 } 7710 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7711 for (r = 0, q = 0; r < numSubcells; ++r) { 7712 /* TODO Map from coarse to fine cells */ 7713 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7714 /* Compress out points not in the section */ 7715 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7716 for (p = 0; p < numFPoints*2; p += 2) { 7717 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7718 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7719 if (!dof) continue; 7720 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7721 if (s < q) continue; 7722 ftotpoints[q*2] = fpoints[p]; 7723 ftotpoints[q*2+1] = fpoints[p+1]; 7724 ++q; 7725 } 7726 } 7727 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7728 } 7729 numFPoints = q; 7730 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7731 PetscInt fdof; 7732 7733 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7734 if (!dof) continue; 7735 for (f = 0; f < numFields; ++f) { 7736 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7737 foffsets[f+1] += fdof; 7738 } 7739 numFIndices += dof; 7740 } 7741 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7742 7743 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7744 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7745 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7746 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7747 if (numFields) { 7748 const PetscInt **permsF[32] = {NULL}; 7749 const PetscInt **permsC[32] = {NULL}; 7750 7751 for (f = 0; f < numFields; f++) { 7752 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7753 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7754 } 7755 for (p = 0; p < numFPoints; p++) { 7756 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7757 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7758 } 7759 for (p = 0; p < numCPoints; p++) { 7760 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7761 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7762 } 7763 for (f = 0; f < numFields; f++) { 7764 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7765 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7766 } 7767 } else { 7768 const PetscInt **permsF = NULL; 7769 const PetscInt **permsC = NULL; 7770 7771 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7772 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7773 for (p = 0, off = 0; p < numFPoints; p++) { 7774 const PetscInt *perm = permsF ? permsF[p] : NULL; 7775 7776 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7777 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7778 } 7779 for (p = 0, off = 0; p < numCPoints; p++) { 7780 const PetscInt *perm = permsC ? permsC[p] : NULL; 7781 7782 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7783 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7784 } 7785 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7786 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7787 } 7788 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7789 /* TODO: flips */ 7790 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7791 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7792 if (ierr) { 7793 PetscMPIInt rank; 7794 7795 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7796 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7797 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7798 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7799 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7800 } 7801 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7802 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7803 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7804 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7805 PetscFunctionReturn(0); 7806 } 7807 7808 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7809 { 7810 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7811 PetscInt *cpoints = NULL; 7812 PetscInt foffsets[32], coffsets[32]; 7813 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7814 DMPolytopeType ct; 7815 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7816 7817 PetscFunctionBegin; 7818 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7819 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7820 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7821 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7822 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7823 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7824 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7825 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7826 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7827 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7828 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7829 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7830 PetscCall(PetscArrayzero(foffsets, 32)); 7831 PetscCall(PetscArrayzero(coffsets, 32)); 7832 /* Column indices */ 7833 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7834 maxFPoints = numCPoints; 7835 /* Compress out points not in the section */ 7836 /* TODO: Squeeze out points with 0 dof as well */ 7837 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7838 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7839 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7840 cpoints[q*2] = cpoints[p]; 7841 cpoints[q*2+1] = cpoints[p+1]; 7842 ++q; 7843 } 7844 } 7845 numCPoints = q; 7846 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7847 PetscInt fdof; 7848 7849 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7850 if (!dof) continue; 7851 for (f = 0; f < numFields; ++f) { 7852 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7853 coffsets[f+1] += fdof; 7854 } 7855 numCIndices += dof; 7856 } 7857 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7858 /* Row indices */ 7859 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7860 { 7861 DMPlexTransform tr; 7862 DMPolytopeType *rct; 7863 PetscInt *rsize, *rcone, *rornt, Nt; 7864 7865 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7866 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7867 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7868 numSubcells = rsize[Nt-1]; 7869 PetscCall(DMPlexTransformDestroy(&tr)); 7870 } 7871 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7872 for (r = 0, q = 0; r < numSubcells; ++r) { 7873 /* TODO Map from coarse to fine cells */ 7874 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7875 /* Compress out points not in the section */ 7876 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7877 for (p = 0; p < numFPoints*2; p += 2) { 7878 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7879 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7880 if (!dof) continue; 7881 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7882 if (s < q) continue; 7883 ftotpoints[q*2] = fpoints[p]; 7884 ftotpoints[q*2+1] = fpoints[p+1]; 7885 ++q; 7886 } 7887 } 7888 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7889 } 7890 numFPoints = q; 7891 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7892 PetscInt fdof; 7893 7894 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7895 if (!dof) continue; 7896 for (f = 0; f < numFields; ++f) { 7897 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7898 foffsets[f+1] += fdof; 7899 } 7900 numFIndices += dof; 7901 } 7902 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7903 7904 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7905 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7906 if (numFields) { 7907 const PetscInt **permsF[32] = {NULL}; 7908 const PetscInt **permsC[32] = {NULL}; 7909 7910 for (f = 0; f < numFields; f++) { 7911 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7912 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7913 } 7914 for (p = 0; p < numFPoints; p++) { 7915 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7916 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7917 } 7918 for (p = 0; p < numCPoints; p++) { 7919 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7920 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7921 } 7922 for (f = 0; f < numFields; f++) { 7923 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7924 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7925 } 7926 } else { 7927 const PetscInt **permsF = NULL; 7928 const PetscInt **permsC = NULL; 7929 7930 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7931 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7932 for (p = 0, off = 0; p < numFPoints; p++) { 7933 const PetscInt *perm = permsF ? permsF[p] : NULL; 7934 7935 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7936 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7937 } 7938 for (p = 0, off = 0; p < numCPoints; p++) { 7939 const PetscInt *perm = permsC ? permsC[p] : NULL; 7940 7941 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7942 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7943 } 7944 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7945 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7946 } 7947 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7948 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7949 PetscFunctionReturn(0); 7950 } 7951 7952 /*@C 7953 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7954 7955 Input Parameter: 7956 . dm - The DMPlex object 7957 7958 Output Parameter: 7959 . cellHeight - The height of a cell 7960 7961 Level: developer 7962 7963 .seealso `DMPlexSetVTKCellHeight()` 7964 @*/ 7965 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7966 { 7967 DM_Plex *mesh = (DM_Plex*) dm->data; 7968 7969 PetscFunctionBegin; 7970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7971 PetscValidIntPointer(cellHeight, 2); 7972 *cellHeight = mesh->vtkCellHeight; 7973 PetscFunctionReturn(0); 7974 } 7975 7976 /*@C 7977 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7978 7979 Input Parameters: 7980 + dm - The DMPlex object 7981 - cellHeight - The height of a cell 7982 7983 Level: developer 7984 7985 .seealso `DMPlexGetVTKCellHeight()` 7986 @*/ 7987 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7988 { 7989 DM_Plex *mesh = (DM_Plex*) dm->data; 7990 7991 PetscFunctionBegin; 7992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7993 mesh->vtkCellHeight = cellHeight; 7994 PetscFunctionReturn(0); 7995 } 7996 7997 /*@ 7998 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7999 8000 Input Parameter: 8001 . dm - The DMPlex object 8002 8003 Output Parameters: 8004 + gcStart - The first ghost cell, or NULL 8005 - gcEnd - The upper bound on ghost cells, or NULL 8006 8007 Level: advanced 8008 8009 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8010 @*/ 8011 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8012 { 8013 DMLabel ctLabel; 8014 8015 PetscFunctionBegin; 8016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8017 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8018 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8019 // Reset label for fast lookup 8020 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8021 PetscFunctionReturn(0); 8022 } 8023 8024 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8025 { 8026 PetscSection section, globalSection; 8027 PetscInt *numbers, p; 8028 8029 PetscFunctionBegin; 8030 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8031 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8032 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8033 for (p = pStart; p < pEnd; ++p) { 8034 PetscCall(PetscSectionSetDof(section, p, 1)); 8035 } 8036 PetscCall(PetscSectionSetUp(section)); 8037 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8038 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8039 for (p = pStart; p < pEnd; ++p) { 8040 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8041 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8042 else numbers[p-pStart] += shift; 8043 } 8044 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8045 if (globalSize) { 8046 PetscLayout layout; 8047 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8048 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8049 PetscCall(PetscLayoutDestroy(&layout)); 8050 } 8051 PetscCall(PetscSectionDestroy(§ion)); 8052 PetscCall(PetscSectionDestroy(&globalSection)); 8053 PetscFunctionReturn(0); 8054 } 8055 8056 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8057 { 8058 PetscInt cellHeight, cStart, cEnd; 8059 8060 PetscFunctionBegin; 8061 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8062 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8063 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8064 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8065 PetscFunctionReturn(0); 8066 } 8067 8068 /*@ 8069 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8070 8071 Input Parameter: 8072 . dm - The DMPlex object 8073 8074 Output Parameter: 8075 . globalCellNumbers - Global cell numbers for all cells on this process 8076 8077 Level: developer 8078 8079 .seealso `DMPlexGetVertexNumbering()` 8080 @*/ 8081 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8082 { 8083 DM_Plex *mesh = (DM_Plex*) dm->data; 8084 8085 PetscFunctionBegin; 8086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8087 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8088 *globalCellNumbers = mesh->globalCellNumbers; 8089 PetscFunctionReturn(0); 8090 } 8091 8092 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8093 { 8094 PetscInt vStart, vEnd; 8095 8096 PetscFunctionBegin; 8097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8098 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8099 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8100 PetscFunctionReturn(0); 8101 } 8102 8103 /*@ 8104 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8105 8106 Input Parameter: 8107 . dm - The DMPlex object 8108 8109 Output Parameter: 8110 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8111 8112 Level: developer 8113 8114 .seealso `DMPlexGetCellNumbering()` 8115 @*/ 8116 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8117 { 8118 DM_Plex *mesh = (DM_Plex*) dm->data; 8119 8120 PetscFunctionBegin; 8121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8122 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8123 *globalVertexNumbers = mesh->globalVertexNumbers; 8124 PetscFunctionReturn(0); 8125 } 8126 8127 /*@ 8128 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8129 8130 Input Parameter: 8131 . dm - The DMPlex object 8132 8133 Output Parameter: 8134 . globalPointNumbers - Global numbers for all points on this process 8135 8136 Level: developer 8137 8138 .seealso `DMPlexGetCellNumbering()` 8139 @*/ 8140 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8141 { 8142 IS nums[4]; 8143 PetscInt depths[4], gdepths[4], starts[4]; 8144 PetscInt depth, d, shift = 0; 8145 8146 PetscFunctionBegin; 8147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8148 PetscCall(DMPlexGetDepth(dm, &depth)); 8149 /* For unstratified meshes use dim instead of depth */ 8150 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8151 for (d = 0; d <= depth; ++d) { 8152 PetscInt end; 8153 8154 depths[d] = depth-d; 8155 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8156 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8157 } 8158 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8159 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8160 for (d = 0; d <= depth; ++d) { 8161 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]); 8162 } 8163 for (d = 0; d <= depth; ++d) { 8164 PetscInt pStart, pEnd, gsize; 8165 8166 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8167 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8168 shift += gsize; 8169 } 8170 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8171 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8172 PetscFunctionReturn(0); 8173 } 8174 8175 /*@ 8176 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8177 8178 Input Parameter: 8179 . dm - The DMPlex object 8180 8181 Output Parameter: 8182 . ranks - The rank field 8183 8184 Options Database Keys: 8185 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8186 8187 Level: intermediate 8188 8189 .seealso: `DMView()` 8190 @*/ 8191 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8192 { 8193 DM rdm; 8194 PetscFE fe; 8195 PetscScalar *r; 8196 PetscMPIInt rank; 8197 DMPolytopeType ct; 8198 PetscInt dim, cStart, cEnd, c; 8199 PetscBool simplex; 8200 8201 PetscFunctionBeginUser; 8202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8203 PetscValidPointer(ranks, 2); 8204 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8205 PetscCall(DMClone(dm, &rdm)); 8206 PetscCall(DMGetDimension(rdm, &dim)); 8207 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8208 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8209 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8210 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8211 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8212 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8213 PetscCall(PetscFEDestroy(&fe)); 8214 PetscCall(DMCreateDS(rdm)); 8215 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8216 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8217 PetscCall(VecGetArray(*ranks, &r)); 8218 for (c = cStart; c < cEnd; ++c) { 8219 PetscScalar *lr; 8220 8221 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8222 if (lr) *lr = rank; 8223 } 8224 PetscCall(VecRestoreArray(*ranks, &r)); 8225 PetscCall(DMDestroy(&rdm)); 8226 PetscFunctionReturn(0); 8227 } 8228 8229 /*@ 8230 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8231 8232 Input Parameters: 8233 + dm - The DMPlex 8234 - label - The DMLabel 8235 8236 Output Parameter: 8237 . val - The label value field 8238 8239 Options Database Keys: 8240 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8241 8242 Level: intermediate 8243 8244 .seealso: `DMView()` 8245 @*/ 8246 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8247 { 8248 DM rdm; 8249 PetscFE fe; 8250 PetscScalar *v; 8251 PetscInt dim, cStart, cEnd, c; 8252 8253 PetscFunctionBeginUser; 8254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8255 PetscValidPointer(label, 2); 8256 PetscValidPointer(val, 3); 8257 PetscCall(DMClone(dm, &rdm)); 8258 PetscCall(DMGetDimension(rdm, &dim)); 8259 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8260 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8261 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8262 PetscCall(PetscFEDestroy(&fe)); 8263 PetscCall(DMCreateDS(rdm)); 8264 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8265 PetscCall(DMCreateGlobalVector(rdm, val)); 8266 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8267 PetscCall(VecGetArray(*val, &v)); 8268 for (c = cStart; c < cEnd; ++c) { 8269 PetscScalar *lv; 8270 PetscInt cval; 8271 8272 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8273 PetscCall(DMLabelGetValue(label, c, &cval)); 8274 *lv = cval; 8275 } 8276 PetscCall(VecRestoreArray(*val, &v)); 8277 PetscCall(DMDestroy(&rdm)); 8278 PetscFunctionReturn(0); 8279 } 8280 8281 /*@ 8282 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8283 8284 Input Parameter: 8285 . dm - The DMPlex object 8286 8287 Notes: 8288 This is a useful diagnostic when creating meshes programmatically. 8289 8290 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8291 8292 Level: developer 8293 8294 .seealso: `DMCreate()`, `DMSetFromOptions()` 8295 @*/ 8296 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8297 { 8298 PetscSection coneSection, supportSection; 8299 const PetscInt *cone, *support; 8300 PetscInt coneSize, c, supportSize, s; 8301 PetscInt pStart, pEnd, p, pp, csize, ssize; 8302 PetscBool storagecheck = PETSC_TRUE; 8303 8304 PetscFunctionBegin; 8305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8306 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8307 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8308 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8309 /* Check that point p is found in the support of its cone points, and vice versa */ 8310 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8311 for (p = pStart; p < pEnd; ++p) { 8312 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8313 PetscCall(DMPlexGetCone(dm, p, &cone)); 8314 for (c = 0; c < coneSize; ++c) { 8315 PetscBool dup = PETSC_FALSE; 8316 PetscInt d; 8317 for (d = c-1; d >= 0; --d) { 8318 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8319 } 8320 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8321 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8322 for (s = 0; s < supportSize; ++s) { 8323 if (support[s] == p) break; 8324 } 8325 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8326 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8327 for (s = 0; s < coneSize; ++s) { 8328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8329 } 8330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8332 for (s = 0; s < supportSize; ++s) { 8333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8334 } 8335 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8336 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]); 8337 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8338 } 8339 } 8340 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8341 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8342 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8343 PetscCall(DMPlexGetSupport(dm, p, &support)); 8344 for (s = 0; s < supportSize; ++s) { 8345 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8346 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8347 for (c = 0; c < coneSize; ++c) { 8348 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8349 if (cone[c] != pp) { c = 0; break; } 8350 if (cone[c] == p) break; 8351 } 8352 if (c >= coneSize) { 8353 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8354 for (c = 0; c < supportSize; ++c) { 8355 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8356 } 8357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8358 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8359 for (c = 0; c < coneSize; ++c) { 8360 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8361 } 8362 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8363 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8364 } 8365 } 8366 } 8367 if (storagecheck) { 8368 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8369 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8370 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8371 } 8372 PetscFunctionReturn(0); 8373 } 8374 8375 /* 8376 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. 8377 */ 8378 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8379 { 8380 DMPolytopeType cct; 8381 PetscInt ptpoints[4]; 8382 const PetscInt *cone, *ccone, *ptcone; 8383 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8384 8385 PetscFunctionBegin; 8386 *unsplit = 0; 8387 switch (ct) { 8388 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8389 ptpoints[npt++] = c; 8390 break; 8391 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8392 PetscCall(DMPlexGetCone(dm, c, &cone)); 8393 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8394 for (cp = 0; cp < coneSize; ++cp) { 8395 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8396 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8397 } 8398 break; 8399 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8400 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8401 PetscCall(DMPlexGetCone(dm, c, &cone)); 8402 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8403 for (cp = 0; cp < coneSize; ++cp) { 8404 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8405 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8406 for (ccp = 0; ccp < cconeSize; ++ccp) { 8407 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8408 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8409 PetscInt p; 8410 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8411 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8412 } 8413 } 8414 } 8415 break; 8416 default: break; 8417 } 8418 for (pt = 0; pt < npt; ++pt) { 8419 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8420 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8421 } 8422 PetscFunctionReturn(0); 8423 } 8424 8425 /*@ 8426 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8427 8428 Input Parameters: 8429 + dm - The DMPlex object 8430 - cellHeight - Normally 0 8431 8432 Notes: 8433 This is a useful diagnostic when creating meshes programmatically. 8434 Currently applicable only to homogeneous simplex or tensor meshes. 8435 8436 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8437 8438 Level: developer 8439 8440 .seealso: `DMCreate()`, `DMSetFromOptions()` 8441 @*/ 8442 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8443 { 8444 DMPlexInterpolatedFlag interp; 8445 DMPolytopeType ct; 8446 PetscInt vStart, vEnd, cStart, cEnd, c; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8450 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8451 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8452 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8453 for (c = cStart; c < cEnd; ++c) { 8454 PetscInt *closure = NULL; 8455 PetscInt coneSize, closureSize, cl, Nv = 0; 8456 8457 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8458 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8459 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8460 if (interp == DMPLEX_INTERPOLATED_FULL) { 8461 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8462 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)); 8463 } 8464 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8465 for (cl = 0; cl < closureSize*2; cl += 2) { 8466 const PetscInt p = closure[cl]; 8467 if ((p >= vStart) && (p < vEnd)) ++Nv; 8468 } 8469 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8470 /* Special Case: Tensor faces with identified vertices */ 8471 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8472 PetscInt unsplit; 8473 8474 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8475 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8476 } 8477 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)); 8478 } 8479 PetscFunctionReturn(0); 8480 } 8481 8482 /*@ 8483 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8484 8485 Collective 8486 8487 Input Parameters: 8488 + dm - The DMPlex object 8489 - cellHeight - Normally 0 8490 8491 Notes: 8492 This is a useful diagnostic when creating meshes programmatically. 8493 This routine is only relevant for meshes that are fully interpolated across all ranks. 8494 It will error out if a partially interpolated mesh is given on some rank. 8495 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8496 8497 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8498 8499 Level: developer 8500 8501 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8502 @*/ 8503 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8504 { 8505 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8506 DMPlexInterpolatedFlag interpEnum; 8507 8508 PetscFunctionBegin; 8509 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8510 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8511 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8512 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8513 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8514 PetscFunctionReturn(0); 8515 } 8516 8517 PetscCall(DMGetDimension(dm, &dim)); 8518 PetscCall(DMPlexGetDepth(dm, &depth)); 8519 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8520 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8521 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8522 for (c = cStart; c < cEnd; ++c) { 8523 const PetscInt *cone, *ornt, *faceSizes, *faces; 8524 const DMPolytopeType *faceTypes; 8525 DMPolytopeType ct; 8526 PetscInt numFaces, coneSize, f; 8527 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8528 8529 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8530 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8531 if (unsplit) continue; 8532 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8533 PetscCall(DMPlexGetCone(dm, c, &cone)); 8534 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8535 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8536 for (cl = 0; cl < closureSize*2; cl += 2) { 8537 const PetscInt p = closure[cl]; 8538 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8539 } 8540 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8541 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); 8542 for (f = 0; f < numFaces; ++f) { 8543 DMPolytopeType fct; 8544 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8545 8546 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8547 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8548 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8549 const PetscInt p = fclosure[cl]; 8550 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8551 } 8552 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]); 8553 for (v = 0; v < fnumCorners; ++v) { 8554 if (fclosure[v] != faces[fOff+v]) { 8555 PetscInt v1; 8556 8557 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8558 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8559 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8560 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8561 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8562 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]); 8563 } 8564 } 8565 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8566 fOff += faceSizes[f]; 8567 } 8568 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8569 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8570 } 8571 } 8572 PetscFunctionReturn(0); 8573 } 8574 8575 /*@ 8576 DMPlexCheckGeometry - Check the geometry of mesh cells 8577 8578 Input Parameter: 8579 . dm - The DMPlex object 8580 8581 Notes: 8582 This is a useful diagnostic when creating meshes programmatically. 8583 8584 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8585 8586 Level: developer 8587 8588 .seealso: `DMCreate()`, `DMSetFromOptions()` 8589 @*/ 8590 PetscErrorCode DMPlexCheckGeometry(DM dm) 8591 { 8592 Vec coordinates; 8593 PetscReal detJ, J[9], refVol = 1.0; 8594 PetscReal vol; 8595 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8596 8597 PetscFunctionBegin; 8598 PetscCall(DMGetDimension(dm, &dim)); 8599 PetscCall(DMGetCoordinateDim(dm, &dE)); 8600 if (dim != dE) PetscFunctionReturn(0); 8601 PetscCall(DMPlexGetDepth(dm, &depth)); 8602 for (d = 0; d < dim; ++d) refVol *= 2.0; 8603 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8604 /* Make sure local coordinates are created, because that step is collective */ 8605 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8606 for (c = cStart; c < cEnd; ++c) { 8607 DMPolytopeType ct; 8608 PetscInt unsplit; 8609 PetscBool ignoreZeroVol = PETSC_FALSE; 8610 8611 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8612 switch (ct) { 8613 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8614 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8615 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8616 ignoreZeroVol = PETSC_TRUE; break; 8617 default: break; 8618 } 8619 switch (ct) { 8620 case DM_POLYTOPE_TRI_PRISM: 8621 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8622 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8623 case DM_POLYTOPE_PYRAMID: 8624 continue; 8625 default: break; 8626 } 8627 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8628 if (unsplit) continue; 8629 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8630 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); 8631 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8632 /* This should work with periodicity since DG coordinates should be used */ 8633 if (depth > 1) { 8634 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8635 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); 8636 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8637 } 8638 } 8639 PetscFunctionReturn(0); 8640 } 8641 8642 /*@ 8643 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8644 8645 Collective 8646 8647 Input Parameters: 8648 + dm - The DMPlex object 8649 - pointSF - The Point SF, or NULL for Point SF attached to DM 8650 8651 Notes: 8652 This is mainly intended for debugging/testing purposes. 8653 8654 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8655 8656 Level: developer 8657 8658 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8659 @*/ 8660 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8661 { 8662 PetscInt l, nleaves, nroots, overlap; 8663 const PetscInt *locals; 8664 const PetscSFNode *remotes; 8665 PetscBool distributed; 8666 MPI_Comm comm; 8667 PetscMPIInt rank; 8668 8669 PetscFunctionBegin; 8670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8671 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8672 else pointSF = dm->sf; 8673 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8674 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8675 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8676 { 8677 PetscMPIInt mpiFlag; 8678 8679 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8680 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8681 } 8682 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8683 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8684 if (!distributed) { 8685 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); 8686 PetscFunctionReturn(0); 8687 } 8688 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); 8689 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8690 8691 /* Check SF graph is compatible with DMPlex chart */ 8692 { 8693 PetscInt pStart, pEnd, maxLeaf; 8694 8695 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8696 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8697 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8698 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8699 } 8700 8701 /* Check Point SF has no local points referenced */ 8702 for (l = 0; l < nleaves; l++) { 8703 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); 8704 } 8705 8706 /* Check there are no cells in interface */ 8707 if (!overlap) { 8708 PetscInt cellHeight, cStart, cEnd; 8709 8710 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8711 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8712 for (l = 0; l < nleaves; ++l) { 8713 const PetscInt point = locals ? locals[l] : l; 8714 8715 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8716 } 8717 } 8718 8719 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8720 { 8721 const PetscInt *rootdegree; 8722 8723 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8724 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8725 for (l = 0; l < nleaves; ++l) { 8726 const PetscInt point = locals ? locals[l] : l; 8727 const PetscInt *cone; 8728 PetscInt coneSize, c, idx; 8729 8730 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8731 PetscCall(DMPlexGetCone(dm, point, &cone)); 8732 for (c = 0; c < coneSize; ++c) { 8733 if (!rootdegree[cone[c]]) { 8734 if (locals) { 8735 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8736 } else { 8737 idx = (cone[c] < nleaves) ? cone[c] : -1; 8738 } 8739 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8740 } 8741 } 8742 } 8743 } 8744 PetscFunctionReturn(0); 8745 } 8746 8747 /*@ 8748 DMPlexCheck - Perform various checks of Plex sanity 8749 8750 Input Parameter: 8751 . dm - The DMPlex object 8752 8753 Notes: 8754 This is a useful diagnostic when creating meshes programmatically. 8755 8756 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8757 8758 Currently does not include DMPlexCheckCellShape(). 8759 8760 Level: developer 8761 8762 .seealso: DMCreate(), DMSetFromOptions() 8763 @*/ 8764 PetscErrorCode DMPlexCheck(DM dm) 8765 { 8766 PetscInt cellHeight; 8767 8768 PetscFunctionBegin; 8769 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8770 PetscCall(DMPlexCheckSymmetry(dm)); 8771 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8772 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8773 PetscCall(DMPlexCheckGeometry(dm)); 8774 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8775 PetscCall(DMPlexCheckInterfaceCones(dm)); 8776 PetscFunctionReturn(0); 8777 } 8778 8779 typedef struct cell_stats 8780 { 8781 PetscReal min, max, sum, squaresum; 8782 PetscInt count; 8783 } cell_stats_t; 8784 8785 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8786 { 8787 PetscInt i, N = *len; 8788 8789 for (i = 0; i < N; i++) { 8790 cell_stats_t *A = (cell_stats_t *) a; 8791 cell_stats_t *B = (cell_stats_t *) b; 8792 8793 B->min = PetscMin(A->min,B->min); 8794 B->max = PetscMax(A->max,B->max); 8795 B->sum += A->sum; 8796 B->squaresum += A->squaresum; 8797 B->count += A->count; 8798 } 8799 } 8800 8801 /*@ 8802 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8803 8804 Collective on dm 8805 8806 Input Parameters: 8807 + dm - The DMPlex object 8808 . output - If true, statistics will be displayed on stdout 8809 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8810 8811 Notes: 8812 This is mainly intended for debugging/testing purposes. 8813 8814 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8815 8816 Level: developer 8817 8818 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8819 @*/ 8820 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8821 { 8822 DM dmCoarse; 8823 cell_stats_t stats, globalStats; 8824 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8825 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8826 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8827 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8828 PetscMPIInt rank,size; 8829 8830 PetscFunctionBegin; 8831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8832 stats.min = PETSC_MAX_REAL; 8833 stats.max = PETSC_MIN_REAL; 8834 stats.sum = stats.squaresum = 0.; 8835 stats.count = 0; 8836 8837 PetscCallMPI(MPI_Comm_size(comm, &size)); 8838 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8839 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8840 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8841 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8842 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8843 for (c = cStart; c < cEnd; c++) { 8844 PetscInt i; 8845 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8846 8847 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8848 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8849 for (i = 0; i < PetscSqr(cdim); ++i) { 8850 frobJ += J[i] * J[i]; 8851 frobInvJ += invJ[i] * invJ[i]; 8852 } 8853 cond2 = frobJ * frobInvJ; 8854 cond = PetscSqrtReal(cond2); 8855 8856 stats.min = PetscMin(stats.min,cond); 8857 stats.max = PetscMax(stats.max,cond); 8858 stats.sum += cond; 8859 stats.squaresum += cond2; 8860 stats.count++; 8861 if (output && cond > limit) { 8862 PetscSection coordSection; 8863 Vec coordsLocal; 8864 PetscScalar *coords = NULL; 8865 PetscInt Nv, d, clSize, cl, *closure = NULL; 8866 8867 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8868 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8869 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8870 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8871 for (i = 0; i < Nv/cdim; ++i) { 8872 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8873 for (d = 0; d < cdim; ++d) { 8874 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8875 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8876 } 8877 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8878 } 8879 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8880 for (cl = 0; cl < clSize*2; cl += 2) { 8881 const PetscInt edge = closure[cl]; 8882 8883 if ((edge >= eStart) && (edge < eEnd)) { 8884 PetscReal len; 8885 8886 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8887 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8888 } 8889 } 8890 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8891 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8892 } 8893 } 8894 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8895 8896 if (size > 1) { 8897 PetscMPIInt blockLengths[2] = {4,1}; 8898 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8899 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8900 MPI_Op statReduce; 8901 8902 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8903 PetscCallMPI(MPI_Type_commit(&statType)); 8904 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8905 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8906 PetscCallMPI(MPI_Op_free(&statReduce)); 8907 PetscCallMPI(MPI_Type_free(&statType)); 8908 } else { 8909 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8910 } 8911 if (rank == 0) { 8912 count = globalStats.count; 8913 min = globalStats.min; 8914 max = globalStats.max; 8915 mean = globalStats.sum / globalStats.count; 8916 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8917 } 8918 8919 if (output) { 8920 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)); 8921 } 8922 PetscCall(PetscFree2(J,invJ)); 8923 8924 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8925 if (dmCoarse) { 8926 PetscBool isplex; 8927 8928 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8929 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8930 } 8931 PetscFunctionReturn(0); 8932 } 8933 8934 /*@ 8935 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8936 orthogonal quality below given tolerance. 8937 8938 Collective on dm 8939 8940 Input Parameters: 8941 + dm - The DMPlex object 8942 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8943 - atol - [0, 1] Absolute tolerance for tagging cells. 8944 8945 Output Parameters: 8946 + OrthQual - Vec containing orthogonal quality per cell 8947 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8948 8949 Options Database Keys: 8950 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8951 supported. 8952 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8953 8954 Notes: 8955 Orthogonal quality is given by the following formula: 8956 8957 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8958 8959 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 8960 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8961 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8962 calculating the cosine of the angle between these vectors. 8963 8964 Orthogonal quality ranges from 1 (best) to 0 (worst). 8965 8966 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8967 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8968 8969 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8970 8971 Level: intermediate 8972 8973 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8974 @*/ 8975 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8976 { 8977 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8978 PetscInt *idx; 8979 PetscScalar *oqVals; 8980 const PetscScalar *cellGeomArr, *faceGeomArr; 8981 PetscReal *ci, *fi, *Ai; 8982 MPI_Comm comm; 8983 Vec cellgeom, facegeom; 8984 DM dmFace, dmCell; 8985 IS glob; 8986 ISLocalToGlobalMapping ltog; 8987 PetscViewer vwr; 8988 8989 PetscFunctionBegin; 8990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8991 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8992 PetscValidPointer(OrthQual, 4); 8993 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8994 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8995 PetscCall(DMGetDimension(dm, &nc)); 8996 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8997 { 8998 DMPlexInterpolatedFlag interpFlag; 8999 9000 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9001 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9002 PetscMPIInt rank; 9003 9004 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9005 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9006 } 9007 } 9008 if (OrthQualLabel) { 9009 PetscValidPointer(OrthQualLabel, 5); 9010 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9011 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9012 } else {*OrthQualLabel = NULL;} 9013 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9014 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9015 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9016 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9017 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9018 PetscCall(VecCreate(comm, OrthQual)); 9019 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9020 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9021 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9022 PetscCall(VecSetUp(*OrthQual)); 9023 PetscCall(ISDestroy(&glob)); 9024 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9025 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9026 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9027 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9028 PetscCall(VecGetDM(cellgeom, &dmCell)); 9029 PetscCall(VecGetDM(facegeom, &dmFace)); 9030 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9031 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9032 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9033 PetscInt cellarr[2], *adj = NULL; 9034 PetscScalar *cArr, *fArr; 9035 PetscReal minvalc = 1.0, minvalf = 1.0; 9036 PetscFVCellGeom *cg; 9037 9038 idx[cellIter] = cell-cStart; 9039 cellarr[0] = cell; 9040 /* Make indexing into cellGeom easier */ 9041 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9042 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9043 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9044 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9045 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9046 PetscInt i; 9047 const PetscInt neigh = adj[cellneigh]; 9048 PetscReal normci = 0, normfi = 0, normai = 0; 9049 PetscFVCellGeom *cgneigh; 9050 PetscFVFaceGeom *fg; 9051 9052 /* Don't count ourselves in the neighbor list */ 9053 if (neigh == cell) continue; 9054 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9055 cellarr[1] = neigh; 9056 { 9057 PetscInt numcovpts; 9058 const PetscInt *covpts; 9059 9060 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9061 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9062 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9063 } 9064 9065 /* Compute c_i, f_i and their norms */ 9066 for (i = 0; i < nc; i++) { 9067 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9068 fi[i] = fg->centroid[i] - cg->centroid[i]; 9069 Ai[i] = fg->normal[i]; 9070 normci += PetscPowReal(ci[i], 2); 9071 normfi += PetscPowReal(fi[i], 2); 9072 normai += PetscPowReal(Ai[i], 2); 9073 } 9074 normci = PetscSqrtReal(normci); 9075 normfi = PetscSqrtReal(normfi); 9076 normai = PetscSqrtReal(normai); 9077 9078 /* Normalize and compute for each face-cell-normal pair */ 9079 for (i = 0; i < nc; i++) { 9080 ci[i] = ci[i]/normci; 9081 fi[i] = fi[i]/normfi; 9082 Ai[i] = Ai[i]/normai; 9083 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9084 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9085 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9086 } 9087 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9088 minvalc = PetscRealPart(cArr[cellneighiter]); 9089 } 9090 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9091 minvalf = PetscRealPart(fArr[cellneighiter]); 9092 } 9093 } 9094 PetscCall(PetscFree(adj)); 9095 PetscCall(PetscFree2(cArr, fArr)); 9096 /* Defer to cell if they're equal */ 9097 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9098 if (OrthQualLabel) { 9099 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9100 } 9101 } 9102 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9103 PetscCall(VecAssemblyBegin(*OrthQual)); 9104 PetscCall(VecAssemblyEnd(*OrthQual)); 9105 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9106 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9107 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9108 if (OrthQualLabel) { 9109 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9110 } 9111 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9112 PetscCall(PetscViewerDestroy(&vwr)); 9113 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9114 PetscFunctionReturn(0); 9115 } 9116 9117 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9118 * interpolator construction */ 9119 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9120 { 9121 PetscSection section, newSection, gsection; 9122 PetscSF sf; 9123 PetscBool hasConstraints, ghasConstraints; 9124 9125 PetscFunctionBegin; 9126 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9127 PetscValidPointer(odm,2); 9128 PetscCall(DMGetLocalSection(dm, §ion)); 9129 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9130 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9131 if (!ghasConstraints) { 9132 PetscCall(PetscObjectReference((PetscObject)dm)); 9133 *odm = dm; 9134 PetscFunctionReturn(0); 9135 } 9136 PetscCall(DMClone(dm, odm)); 9137 PetscCall(DMCopyFields(dm, *odm)); 9138 PetscCall(DMGetLocalSection(*odm, &newSection)); 9139 PetscCall(DMGetPointSF(*odm, &sf)); 9140 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9141 PetscCall(DMSetGlobalSection(*odm, gsection)); 9142 PetscCall(PetscSectionDestroy(&gsection)); 9143 PetscFunctionReturn(0); 9144 } 9145 9146 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9147 { 9148 DM dmco, dmfo; 9149 Mat interpo; 9150 Vec rscale; 9151 Vec cglobalo, clocal; 9152 Vec fglobal, fglobalo, flocal; 9153 PetscBool regular; 9154 9155 PetscFunctionBegin; 9156 PetscCall(DMGetFullDM(dmc, &dmco)); 9157 PetscCall(DMGetFullDM(dmf, &dmfo)); 9158 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9159 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9160 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9161 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9162 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9163 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9164 PetscCall(VecSet(cglobalo, 0.)); 9165 PetscCall(VecSet(clocal, 0.)); 9166 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9167 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9168 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9169 PetscCall(VecSet(fglobal, 0.)); 9170 PetscCall(VecSet(fglobalo, 0.)); 9171 PetscCall(VecSet(flocal, 0.)); 9172 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9173 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9174 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9175 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9176 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9177 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9178 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9179 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9180 *shift = fglobal; 9181 PetscCall(VecDestroy(&flocal)); 9182 PetscCall(VecDestroy(&fglobalo)); 9183 PetscCall(VecDestroy(&clocal)); 9184 PetscCall(VecDestroy(&cglobalo)); 9185 PetscCall(VecDestroy(&rscale)); 9186 PetscCall(MatDestroy(&interpo)); 9187 PetscCall(DMDestroy(&dmfo)); 9188 PetscCall(DMDestroy(&dmco)); 9189 PetscFunctionReturn(0); 9190 } 9191 9192 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9193 { 9194 PetscObject shifto; 9195 Vec shift; 9196 9197 PetscFunctionBegin; 9198 if (!interp) { 9199 Vec rscale; 9200 9201 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9202 PetscCall(VecDestroy(&rscale)); 9203 } else { 9204 PetscCall(PetscObjectReference((PetscObject)interp)); 9205 } 9206 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9207 if (!shifto) { 9208 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9209 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9210 shifto = (PetscObject) shift; 9211 PetscCall(VecDestroy(&shift)); 9212 } 9213 shift = (Vec) shifto; 9214 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9215 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9216 PetscCall(MatDestroy(&interp)); 9217 PetscFunctionReturn(0); 9218 } 9219 9220 /* Pointwise interpolation 9221 Just code FEM for now 9222 u^f = I u^c 9223 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9224 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9225 I_{ij} = psi^f_i phi^c_j 9226 */ 9227 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9228 { 9229 PetscSection gsc, gsf; 9230 PetscInt m, n; 9231 void *ctx; 9232 DM cdm; 9233 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9234 9235 PetscFunctionBegin; 9236 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9237 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9238 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9239 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9240 9241 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9242 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9243 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9244 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9245 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9246 9247 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9248 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9249 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9250 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9251 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9252 if (scaling) { 9253 /* Use naive scaling */ 9254 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9255 } 9256 PetscFunctionReturn(0); 9257 } 9258 9259 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9260 { 9261 VecScatter ctx; 9262 9263 PetscFunctionBegin; 9264 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9265 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9266 PetscCall(VecScatterDestroy(&ctx)); 9267 PetscFunctionReturn(0); 9268 } 9269 9270 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9271 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9272 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9273 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9274 { 9275 const PetscInt Nc = uOff[1] - uOff[0]; 9276 PetscInt c; 9277 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9278 } 9279 9280 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9281 { 9282 DM dmc; 9283 PetscDS ds; 9284 Vec ones, locmass; 9285 IS cellIS; 9286 PetscFormKey key; 9287 PetscInt depth; 9288 9289 PetscFunctionBegin; 9290 PetscCall(DMClone(dm, &dmc)); 9291 PetscCall(DMCopyDisc(dm, dmc)); 9292 PetscCall(DMGetDS(dmc, &ds)); 9293 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9294 PetscCall(DMCreateGlobalVector(dmc, mass)); 9295 PetscCall(DMGetLocalVector(dmc, &ones)); 9296 PetscCall(DMGetLocalVector(dmc, &locmass)); 9297 PetscCall(DMPlexGetDepth(dmc, &depth)); 9298 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9299 PetscCall(VecSet(locmass, 0.0)); 9300 PetscCall(VecSet(ones, 1.0)); 9301 key.label = NULL; 9302 key.value = 0; 9303 key.field = 0; 9304 key.part = 0; 9305 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9306 PetscCall(ISDestroy(&cellIS)); 9307 PetscCall(VecSet(*mass, 0.0)); 9308 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9309 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9310 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9311 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9312 PetscCall(DMDestroy(&dmc)); 9313 PetscFunctionReturn(0); 9314 } 9315 9316 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9317 { 9318 PetscSection gsc, gsf; 9319 PetscInt m, n; 9320 void *ctx; 9321 DM cdm; 9322 PetscBool regular; 9323 9324 PetscFunctionBegin; 9325 if (dmFine == dmCoarse) { 9326 DM dmc; 9327 PetscDS ds; 9328 PetscWeakForm wf; 9329 Vec u; 9330 IS cellIS; 9331 PetscFormKey key; 9332 PetscInt depth; 9333 9334 PetscCall(DMClone(dmFine, &dmc)); 9335 PetscCall(DMCopyDisc(dmFine, dmc)); 9336 PetscCall(DMGetDS(dmc, &ds)); 9337 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9338 PetscCall(PetscWeakFormClear(wf)); 9339 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9340 PetscCall(DMCreateMatrix(dmc, mass)); 9341 PetscCall(DMGetLocalVector(dmc, &u)); 9342 PetscCall(DMPlexGetDepth(dmc, &depth)); 9343 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9344 PetscCall(MatZeroEntries(*mass)); 9345 key.label = NULL; 9346 key.value = 0; 9347 key.field = 0; 9348 key.part = 0; 9349 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9350 PetscCall(ISDestroy(&cellIS)); 9351 PetscCall(DMRestoreLocalVector(dmc, &u)); 9352 PetscCall(DMDestroy(&dmc)); 9353 } else { 9354 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9355 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9356 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9357 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9358 9359 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9360 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9361 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9362 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9363 9364 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9365 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9366 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9367 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9368 } 9369 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9370 PetscFunctionReturn(0); 9371 } 9372 9373 /*@ 9374 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9375 9376 Input Parameter: 9377 . dm - The DMPlex object 9378 9379 Output Parameter: 9380 . regular - The flag 9381 9382 Level: intermediate 9383 9384 .seealso: `DMPlexSetRegularRefinement()` 9385 @*/ 9386 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9387 { 9388 PetscFunctionBegin; 9389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9390 PetscValidBoolPointer(regular, 2); 9391 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9392 PetscFunctionReturn(0); 9393 } 9394 9395 /*@ 9396 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9397 9398 Input Parameters: 9399 + dm - The DMPlex object 9400 - regular - The flag 9401 9402 Level: intermediate 9403 9404 .seealso: `DMPlexGetRegularRefinement()` 9405 @*/ 9406 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9407 { 9408 PetscFunctionBegin; 9409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9410 ((DM_Plex *) dm->data)->regularRefinement = regular; 9411 PetscFunctionReturn(0); 9412 } 9413 9414 /* anchors */ 9415 /*@ 9416 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9417 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9418 9419 not collective 9420 9421 Input Parameter: 9422 . dm - The DMPlex object 9423 9424 Output Parameters: 9425 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9426 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9427 9428 Level: intermediate 9429 9430 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9431 @*/ 9432 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9433 { 9434 DM_Plex *plex = (DM_Plex *)dm->data; 9435 9436 PetscFunctionBegin; 9437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9438 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9439 if (anchorSection) *anchorSection = plex->anchorSection; 9440 if (anchorIS) *anchorIS = plex->anchorIS; 9441 PetscFunctionReturn(0); 9442 } 9443 9444 /*@ 9445 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9446 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9447 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9448 9449 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9450 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9451 9452 collective on dm 9453 9454 Input Parameters: 9455 + dm - The DMPlex object 9456 . 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). 9457 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9458 9459 The reference counts of anchorSection and anchorIS are incremented. 9460 9461 Level: intermediate 9462 9463 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9464 @*/ 9465 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9466 { 9467 DM_Plex *plex = (DM_Plex *)dm->data; 9468 PetscMPIInt result; 9469 9470 PetscFunctionBegin; 9471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9472 if (anchorSection) { 9473 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9474 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9475 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9476 } 9477 if (anchorIS) { 9478 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9479 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9480 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9481 } 9482 9483 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9484 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9485 plex->anchorSection = anchorSection; 9486 9487 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9488 PetscCall(ISDestroy(&plex->anchorIS)); 9489 plex->anchorIS = anchorIS; 9490 9491 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9492 PetscInt size, a, pStart, pEnd; 9493 const PetscInt *anchors; 9494 9495 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9496 PetscCall(ISGetLocalSize(anchorIS,&size)); 9497 PetscCall(ISGetIndices(anchorIS,&anchors)); 9498 for (a = 0; a < size; a++) { 9499 PetscInt p; 9500 9501 p = anchors[a]; 9502 if (p >= pStart && p < pEnd) { 9503 PetscInt dof; 9504 9505 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9506 if (dof) { 9507 9508 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9509 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9510 } 9511 } 9512 } 9513 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9514 } 9515 /* reset the generic constraints */ 9516 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9517 PetscFunctionReturn(0); 9518 } 9519 9520 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9521 { 9522 PetscSection anchorSection; 9523 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9524 9525 PetscFunctionBegin; 9526 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9527 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9528 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9529 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9530 if (numFields) { 9531 PetscInt f; 9532 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9533 9534 for (f = 0; f < numFields; f++) { 9535 PetscInt numComp; 9536 9537 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9538 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9539 } 9540 } 9541 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9542 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9543 pStart = PetscMax(pStart,sStart); 9544 pEnd = PetscMin(pEnd,sEnd); 9545 pEnd = PetscMax(pStart,pEnd); 9546 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9547 for (p = pStart; p < pEnd; p++) { 9548 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9549 if (dof) { 9550 PetscCall(PetscSectionGetDof(section,p,&dof)); 9551 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9552 for (f = 0; f < numFields; f++) { 9553 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9554 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9555 } 9556 } 9557 } 9558 PetscCall(PetscSectionSetUp(*cSec)); 9559 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9560 PetscFunctionReturn(0); 9561 } 9562 9563 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9564 { 9565 PetscSection aSec; 9566 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9567 const PetscInt *anchors; 9568 PetscInt numFields, f; 9569 IS aIS; 9570 MatType mtype; 9571 PetscBool iscuda,iskokkos; 9572 9573 PetscFunctionBegin; 9574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9575 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9576 PetscCall(PetscSectionGetStorageSize(section, &n)); 9577 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9578 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9579 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9580 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9581 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9582 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9583 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9584 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9585 else mtype = MATSEQAIJ; 9586 PetscCall(MatSetType(*cMat,mtype)); 9587 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9588 PetscCall(ISGetIndices(aIS,&anchors)); 9589 /* cSec will be a subset of aSec and section */ 9590 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9591 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9592 PetscCall(PetscMalloc1(m+1,&i)); 9593 i[0] = 0; 9594 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9595 for (p = pStart; p < pEnd; p++) { 9596 PetscInt rDof, rOff, r; 9597 9598 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9599 if (!rDof) continue; 9600 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9601 if (numFields) { 9602 for (f = 0; f < numFields; f++) { 9603 annz = 0; 9604 for (r = 0; r < rDof; r++) { 9605 a = anchors[rOff + r]; 9606 if (a < sStart || a >= sEnd) continue; 9607 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9608 annz += aDof; 9609 } 9610 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9611 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9612 for (q = 0; q < dof; q++) { 9613 i[off + q + 1] = i[off + q] + annz; 9614 } 9615 } 9616 } else { 9617 annz = 0; 9618 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9619 for (q = 0; q < dof; q++) { 9620 a = anchors[rOff + q]; 9621 if (a < sStart || a >= sEnd) continue; 9622 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9623 annz += aDof; 9624 } 9625 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9626 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9627 for (q = 0; q < dof; q++) { 9628 i[off + q + 1] = i[off + q] + annz; 9629 } 9630 } 9631 } 9632 nnz = i[m]; 9633 PetscCall(PetscMalloc1(nnz,&j)); 9634 offset = 0; 9635 for (p = pStart; p < pEnd; p++) { 9636 if (numFields) { 9637 for (f = 0; f < numFields; f++) { 9638 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9639 for (q = 0; q < dof; q++) { 9640 PetscInt rDof, rOff, r; 9641 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9642 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9643 for (r = 0; r < rDof; r++) { 9644 PetscInt s; 9645 9646 a = anchors[rOff + r]; 9647 if (a < sStart || a >= sEnd) continue; 9648 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9649 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9650 for (s = 0; s < aDof; s++) { 9651 j[offset++] = aOff + s; 9652 } 9653 } 9654 } 9655 } 9656 } else { 9657 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9658 for (q = 0; q < dof; q++) { 9659 PetscInt rDof, rOff, r; 9660 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9661 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9662 for (r = 0; r < rDof; r++) { 9663 PetscInt s; 9664 9665 a = anchors[rOff + r]; 9666 if (a < sStart || a >= sEnd) continue; 9667 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9668 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9669 for (s = 0; s < aDof; s++) { 9670 j[offset++] = aOff + s; 9671 } 9672 } 9673 } 9674 } 9675 } 9676 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9677 PetscCall(PetscFree(i)); 9678 PetscCall(PetscFree(j)); 9679 PetscCall(ISRestoreIndices(aIS,&anchors)); 9680 PetscFunctionReturn(0); 9681 } 9682 9683 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9684 { 9685 DM_Plex *plex = (DM_Plex *)dm->data; 9686 PetscSection anchorSection, section, cSec; 9687 Mat cMat; 9688 9689 PetscFunctionBegin; 9690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9691 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9692 if (anchorSection) { 9693 PetscInt Nf; 9694 9695 PetscCall(DMGetLocalSection(dm,§ion)); 9696 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9697 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9698 PetscCall(DMGetNumFields(dm,&Nf)); 9699 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9700 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9701 PetscCall(PetscSectionDestroy(&cSec)); 9702 PetscCall(MatDestroy(&cMat)); 9703 } 9704 PetscFunctionReturn(0); 9705 } 9706 9707 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9708 { 9709 IS subis; 9710 PetscSection section, subsection; 9711 9712 PetscFunctionBegin; 9713 PetscCall(DMGetLocalSection(dm, §ion)); 9714 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9715 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9716 /* Create subdomain */ 9717 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9718 /* Create submodel */ 9719 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9720 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9721 PetscCall(DMSetLocalSection(*subdm, subsection)); 9722 PetscCall(PetscSectionDestroy(&subsection)); 9723 PetscCall(DMCopyDisc(dm, *subdm)); 9724 /* Create map from submodel to global model */ 9725 if (is) { 9726 PetscSection sectionGlobal, subsectionGlobal; 9727 IS spIS; 9728 const PetscInt *spmap; 9729 PetscInt *subIndices; 9730 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9731 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9732 9733 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9734 PetscCall(ISGetIndices(spIS, &spmap)); 9735 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9736 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9737 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9738 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9739 for (p = pStart; p < pEnd; ++p) { 9740 PetscInt gdof, pSubSize = 0; 9741 9742 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9743 if (gdof > 0) { 9744 for (f = 0; f < Nf; ++f) { 9745 PetscInt fdof, fcdof; 9746 9747 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9748 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9749 pSubSize += fdof-fcdof; 9750 } 9751 subSize += pSubSize; 9752 if (pSubSize) { 9753 if (bs < 0) { 9754 bs = pSubSize; 9755 } else if (bs != pSubSize) { 9756 /* Layout does not admit a pointwise block size */ 9757 bs = 1; 9758 } 9759 } 9760 } 9761 } 9762 /* Must have same blocksize on all procs (some might have no points) */ 9763 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9764 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9765 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9766 else {bs = bsMinMax[0];} 9767 PetscCall(PetscMalloc1(subSize, &subIndices)); 9768 for (p = pStart; p < pEnd; ++p) { 9769 PetscInt gdof, goff; 9770 9771 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9772 if (gdof > 0) { 9773 const PetscInt point = spmap[p]; 9774 9775 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9776 for (f = 0; f < Nf; ++f) { 9777 PetscInt fdof, fcdof, fc, f2, poff = 0; 9778 9779 /* Can get rid of this loop by storing field information in the global section */ 9780 for (f2 = 0; f2 < f; ++f2) { 9781 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9782 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9783 poff += fdof-fcdof; 9784 } 9785 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9786 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9787 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9788 subIndices[subOff] = goff+poff+fc; 9789 } 9790 } 9791 } 9792 } 9793 PetscCall(ISRestoreIndices(spIS, &spmap)); 9794 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9795 if (bs > 1) { 9796 /* We need to check that the block size does not come from non-contiguous fields */ 9797 PetscInt i, j, set = 1; 9798 for (i = 0; i < subSize; i += bs) { 9799 for (j = 0; j < bs; ++j) { 9800 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9801 } 9802 } 9803 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9804 } 9805 /* Attach nullspace */ 9806 for (f = 0; f < Nf; ++f) { 9807 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9808 if ((*subdm)->nullspaceConstructors[f]) break; 9809 } 9810 if (f < Nf) { 9811 MatNullSpace nullSpace; 9812 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9813 9814 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9815 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9816 } 9817 } 9818 PetscFunctionReturn(0); 9819 } 9820 9821 /*@ 9822 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9823 9824 Input Parameter: 9825 - dm - The DM 9826 9827 Level: developer 9828 9829 Options Database Keys: 9830 . -dm_plex_monitor_throughput - Activate the monitor 9831 9832 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9833 @*/ 9834 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9835 { 9836 #if defined(PETSC_USE_LOG) 9837 PetscStageLog stageLog; 9838 PetscLogEvent event; 9839 PetscLogStage stage; 9840 PetscEventPerfInfo eventInfo; 9841 PetscReal cellRate, flopRate; 9842 PetscInt cStart, cEnd, Nf, N; 9843 const char *name; 9844 #endif 9845 9846 PetscFunctionBegin; 9847 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9848 #if defined(PETSC_USE_LOG) 9849 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9850 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9851 PetscCall(DMGetNumFields(dm, &Nf)); 9852 PetscCall(PetscLogGetStageLog(&stageLog)); 9853 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9854 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9855 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9856 N = (cEnd - cStart)*Nf*eventInfo.count; 9857 flopRate = eventInfo.flops/eventInfo.time; 9858 cellRate = N/eventInfo.time; 9859 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))); 9860 #else 9861 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9862 #endif 9863 PetscFunctionReturn(0); 9864 } 9865