1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 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; 13 PetscLogEvent DMPLEX_RebalBuildGraph,DMPLEX_RebalRewriteSF,DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 14 15 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 16 17 /*@ 18 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 19 20 Input Parameter: 21 . dm - The DMPlex object 22 23 Output Parameter: 24 . simplex - Flag checking for a simplex 25 26 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 27 If the mesh has no cells, this returns PETSC_FALSE. 28 29 Level: intermediate 30 31 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 32 @*/ 33 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 34 { 35 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 41 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 42 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 43 PetscFunctionReturn(0); 44 } 45 46 /*@ 47 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 48 49 Input Parameters: 50 + dm - The DMPlex object 51 - height - The cell height in the Plex, 0 is the default 52 53 Output Parameters: 54 + cStart - The first "normal" cell 55 - cEnd - The upper bound on "normal"" cells 56 57 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 58 59 Level: developer 60 61 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 62 @*/ 63 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 64 { 65 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 66 PetscInt cS, cE, c; 67 68 PetscFunctionBegin; 69 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 70 for (c = cS; c < cE; ++c) { 71 DMPolytopeType cct; 72 73 PetscCall(DMPlexGetCellType(dm, c, &cct)); 74 if ((PetscInt) cct < 0) break; 75 switch (cct) { 76 case DM_POLYTOPE_POINT: 77 case DM_POLYTOPE_SEGMENT: 78 case DM_POLYTOPE_TRIANGLE: 79 case DM_POLYTOPE_QUADRILATERAL: 80 case DM_POLYTOPE_TETRAHEDRON: 81 case DM_POLYTOPE_HEXAHEDRON: 82 ct = cct; 83 break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 } 94 if (cStart) *cStart = cS; 95 if (cEnd) *cEnd = cE; 96 PetscFunctionReturn(0); 97 } 98 99 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 100 { 101 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 102 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 103 104 PetscFunctionBegin; 105 *ft = PETSC_VTK_INVALID; 106 PetscCall(DMGetCoordinateDim(dm, &cdim)); 107 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 108 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 109 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 110 if (field >= 0) { 111 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 112 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 113 } else { 114 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 115 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 116 } 117 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 118 if (globalvcdof[0]) { 119 *sStart = vStart; 120 *sEnd = vEnd; 121 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 122 else *ft = PETSC_VTK_POINT_FIELD; 123 } else if (globalvcdof[1]) { 124 *sStart = cStart; 125 *sEnd = cEnd; 126 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 127 else *ft = PETSC_VTK_CELL_FIELD; 128 } else { 129 if (field >= 0) { 130 const char *fieldname; 131 132 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 133 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 134 } else { 135 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 136 } 137 } 138 PetscFunctionReturn(0); 139 } 140 141 /*@ 142 DMPlexVecView1D - Plot many 1D solutions on the same line graph 143 144 Collective on dm 145 146 Input Parameters: 147 + dm - The DMPlex 148 . n - The number of vectors 149 . u - The array of local vectors 150 - viewer - The Draw viewer 151 152 Level: advanced 153 154 .seealso: `VecViewFromOptions()`, `VecView()` 155 @*/ 156 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 157 { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 226 { 227 DM dm; 228 229 PetscFunctionBegin; 230 PetscCall(VecGetDM(u, &dm)); 231 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 232 PetscFunctionReturn(0); 233 } 234 235 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 236 { 237 DM dm; 238 PetscSection s; 239 PetscDraw draw, popup; 240 DM cdm; 241 PetscSection coordSection; 242 Vec coordinates; 243 const PetscScalar *coords, *array; 244 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 245 PetscReal vbound[2], time; 246 PetscBool flg; 247 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 248 const char *name; 249 char title[PETSC_MAX_PATH_LEN]; 250 251 PetscFunctionBegin; 252 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 253 PetscCall(VecGetDM(v, &dm)); 254 PetscCall(DMGetCoordinateDim(dm, &dim)); 255 PetscCall(DMGetLocalSection(dm, &s)); 256 PetscCall(PetscSectionGetNumFields(s, &Nf)); 257 PetscCall(DMGetCoarsenLevel(dm, &level)); 258 PetscCall(DMGetCoordinateDM(dm, &cdm)); 259 PetscCall(DMGetLocalSection(cdm, &coordSection)); 260 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 261 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 262 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 263 264 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 265 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 266 267 PetscCall(VecGetLocalSize(coordinates, &N)); 268 PetscCall(VecGetArrayRead(coordinates, &coords)); 269 for (c = 0; c < N; c += dim) { 270 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 271 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 288 else {prefix[0] = '\0';} 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 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); 329 switch (numVals/Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 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])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 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])); 351 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])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 372 { 373 DM dm; 374 PetscDraw draw; 375 PetscInt dim; 376 PetscBool isnull; 377 378 PetscFunctionBegin; 379 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 380 PetscCall(PetscDrawIsNull(draw, &isnull)); 381 if (isnull) PetscFunctionReturn(0); 382 383 PetscCall(VecGetDM(v, &dm)); 384 PetscCall(DMGetCoordinateDim(dm, &dim)); 385 switch (dim) { 386 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 387 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 388 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 389 } 390 PetscFunctionReturn(0); 391 } 392 393 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 394 { 395 DM dm; 396 Vec locv; 397 const char *name; 398 PetscSection section; 399 PetscInt pStart, pEnd; 400 PetscInt numFields; 401 PetscViewerVTKFieldType ft; 402 403 PetscFunctionBegin; 404 PetscCall(VecGetDM(v, &dm)); 405 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 406 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 407 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 408 PetscCall(VecCopy(v, locv)); 409 PetscCall(DMGetLocalSection(dm, §ion)); 410 PetscCall(PetscSectionGetNumFields(section, &numFields)); 411 if (!numFields) { 412 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 413 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 414 } else { 415 PetscInt f; 416 417 for (f = 0; f < numFields; f++) { 418 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 419 if (ft == PETSC_VTK_INVALID) continue; 420 PetscCall(PetscObjectReference((PetscObject)locv)); 421 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 422 } 423 PetscCall(VecDestroy(&locv)); 424 } 425 PetscFunctionReturn(0); 426 } 427 428 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 429 { 430 DM dm; 431 PetscBool isvtk, ishdf5, isdraw, isglvis; 432 433 PetscFunctionBegin; 434 PetscCall(VecGetDM(v, &dm)); 435 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 439 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 440 if (isvtk || ishdf5 || isdraw || isglvis) { 441 PetscInt i,numFields; 442 PetscObject fe; 443 PetscBool fem = PETSC_FALSE; 444 Vec locv = v; 445 const char *name; 446 PetscInt step; 447 PetscReal time; 448 449 PetscCall(DMGetNumFields(dm, &numFields)); 450 for (i=0; i<numFields; i++) { 451 PetscCall(DMGetField(dm, i, NULL, &fe)); 452 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 453 } 454 if (fem) { 455 PetscObject isZero; 456 457 PetscCall(DMGetLocalVector(dm, &locv)); 458 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 459 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 460 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 461 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 462 PetscCall(VecCopy(v, locv)); 463 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 464 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 465 } 466 if (isvtk) { 467 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 468 } else if (ishdf5) { 469 #if defined(PETSC_HAVE_HDF5) 470 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 471 #else 472 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 473 #endif 474 } else if (isdraw) { 475 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 476 } else if (isglvis) { 477 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 478 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 479 PetscCall(VecView_GLVis(locv, viewer)); 480 } 481 if (fem) { 482 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 483 PetscCall(DMRestoreLocalVector(dm, &locv)); 484 } 485 } else { 486 PetscBool isseq; 487 488 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 489 if (isseq) PetscCall(VecView_Seq(v, viewer)); 490 else PetscCall(VecView_MPI(v, viewer)); 491 } 492 PetscFunctionReturn(0); 493 } 494 495 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 496 { 497 DM dm; 498 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 499 500 PetscFunctionBegin; 501 PetscCall(VecGetDM(v, &dm)); 502 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 507 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 508 if (isvtk || isdraw || isglvis) { 509 Vec locv; 510 PetscObject isZero; 511 const char *name; 512 513 PetscCall(DMGetLocalVector(dm, &locv)); 514 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 515 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 516 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 517 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 518 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 519 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 520 PetscCall(VecView_Plex_Local(locv, viewer)); 521 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 522 PetscCall(DMRestoreLocalVector(dm, &locv)); 523 } else if (ishdf5) { 524 #if defined(PETSC_HAVE_HDF5) 525 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 526 #else 527 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 528 #endif 529 } else if (isexodusii) { 530 #if defined(PETSC_HAVE_EXODUSII) 531 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 532 #else 533 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 534 #endif 535 } else { 536 PetscBool isseq; 537 538 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 539 if (isseq) PetscCall(VecView_Seq(v, viewer)); 540 else PetscCall(VecView_MPI(v, viewer)); 541 } 542 PetscFunctionReturn(0); 543 } 544 545 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 546 { 547 DM dm; 548 MPI_Comm comm; 549 PetscViewerFormat format; 550 Vec v; 551 PetscBool isvtk, ishdf5; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(originalv, &dm)); 555 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 556 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscViewerGetFormat(viewer, &format)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 560 if (format == PETSC_VIEWER_NATIVE) { 561 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 562 /* this need a better fix */ 563 if (dm->useNatural) { 564 if (dm->sfNatural) { 565 const char *vecname; 566 PetscInt n, nroots; 567 568 PetscCall(VecGetLocalSize(originalv, &n)); 569 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 570 if (n == nroots) { 571 PetscCall(DMGetGlobalVector(dm, &v)); 572 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 573 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 574 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 575 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 577 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 578 } else v = originalv; 579 } else v = originalv; 580 581 if (ishdf5) { 582 #if defined(PETSC_HAVE_HDF5) 583 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 584 #else 585 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 586 #endif 587 } else if (isvtk) { 588 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 589 } else { 590 PetscBool isseq; 591 592 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 593 if (isseq) PetscCall(VecView_Seq(v, viewer)); 594 else PetscCall(VecView_MPI(v, viewer)); 595 } 596 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 597 PetscFunctionReturn(0); 598 } 599 600 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 601 { 602 DM dm; 603 PetscBool ishdf5; 604 605 PetscFunctionBegin; 606 PetscCall(VecGetDM(v, &dm)); 607 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 608 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 609 if (ishdf5) { 610 DM dmBC; 611 Vec gv; 612 const char *name; 613 614 PetscCall(DMGetOutputDM(dm, &dmBC)); 615 PetscCall(DMGetGlobalVector(dmBC, &gv)); 616 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 617 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 618 PetscCall(VecLoad_Default(gv, viewer)); 619 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 621 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 622 } else PetscCall(VecLoad_Default(v, viewer)); 623 PetscFunctionReturn(0); 624 } 625 626 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool ishdf5,isexodusii; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 636 if (ishdf5) { 637 #if defined(PETSC_HAVE_HDF5) 638 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 639 #else 640 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 641 #endif 642 } else if (isexodusii) { 643 #if defined(PETSC_HAVE_EXODUSII) 644 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 645 #else 646 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 647 #endif 648 } else PetscCall(VecLoad_Default(v, viewer)); 649 PetscFunctionReturn(0); 650 } 651 652 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 653 { 654 DM dm; 655 PetscViewerFormat format; 656 PetscBool ishdf5; 657 658 PetscFunctionBegin; 659 PetscCall(VecGetDM(originalv, &dm)); 660 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 661 PetscCall(PetscViewerGetFormat(viewer, &format)); 662 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 663 if (format == PETSC_VIEWER_NATIVE) { 664 if (dm->useNatural) { 665 if (dm->sfNatural) { 666 if (ishdf5) { 667 #if defined(PETSC_HAVE_HDF5) 668 Vec v; 669 const char *vecname; 670 671 PetscCall(DMGetGlobalVector(dm, &v)); 672 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 673 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 674 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 675 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 676 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 677 PetscCall(DMRestoreGlobalVector(dm, &v)); 678 #else 679 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 680 #endif 681 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 682 } 683 } else PetscCall(VecLoad_Default(originalv, viewer)); 684 } 685 PetscFunctionReturn(0); 686 } 687 688 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 689 { 690 PetscSection coordSection; 691 Vec coordinates; 692 DMLabel depthLabel, celltypeLabel; 693 const char *name[4]; 694 const PetscScalar *a; 695 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 696 697 PetscFunctionBegin; 698 PetscCall(DMGetDimension(dm, &dim)); 699 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 700 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 701 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 702 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 703 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 704 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 705 PetscCall(VecGetArrayRead(coordinates, &a)); 706 name[0] = "vertex"; 707 name[1] = "edge"; 708 name[dim-1] = "face"; 709 name[dim] = "cell"; 710 for (c = cStart; c < cEnd; ++c) { 711 PetscInt *closure = NULL; 712 PetscInt closureSize, cl, ct; 713 714 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 715 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 716 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 717 PetscCall(PetscViewerASCIIPushTab(viewer)); 718 for (cl = 0; cl < closureSize*2; cl += 2) { 719 PetscInt point = closure[cl], depth, dof, off, d, p; 720 721 if ((point < pStart) || (point >= pEnd)) continue; 722 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 723 if (!dof) continue; 724 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 725 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 726 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 727 for (p = 0; p < dof/dim; ++p) { 728 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 729 for (d = 0; d < dim; ++d) { 730 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 732 } 733 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 736 } 737 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 738 PetscCall(PetscViewerASCIIPopTab(viewer)); 739 } 740 PetscCall(VecRestoreArrayRead(coordinates, &a)); 741 PetscFunctionReturn(0); 742 } 743 744 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 745 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 746 747 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 748 { 749 PetscInt i; 750 751 PetscFunctionBegin; 752 if (dim > 3) { 753 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 754 } else { 755 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 756 757 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 758 switch (cs) { 759 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 760 case CS_POLAR: 761 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 762 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 763 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 764 break; 765 case CS_CYLINDRICAL: 766 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 trcoords[2] = coords[2]; 770 break; 771 case CS_SPHERICAL: 772 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 773 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 774 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 775 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 776 break; 777 } 778 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 779 } 780 PetscFunctionReturn(0); 781 } 782 783 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 784 { 785 DM_Plex *mesh = (DM_Plex*) dm->data; 786 DM cdm, cdmCell; 787 PetscSection coordSection, coordSectionCell; 788 Vec coordinates, coordinatesCell; 789 PetscViewerFormat format; 790 791 PetscFunctionBegin; 792 PetscCall(DMGetCoordinateDM(dm, &cdm)); 793 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 794 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 795 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 796 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 797 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 798 PetscCall(PetscViewerGetFormat(viewer, &format)); 799 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 800 const char *name; 801 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 802 PetscInt pStart, pEnd, p, numLabels, l; 803 PetscMPIInt rank, size; 804 805 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 806 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 807 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 808 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 809 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 810 PetscCall(DMGetDimension(dm, &dim)); 811 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 812 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 813 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 814 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 815 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 816 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 817 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 818 for (p = pStart; p < pEnd; ++p) { 819 PetscInt dof, off, s; 820 821 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 822 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 823 for (s = off; s < off+dof; ++s) { 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 825 } 826 } 827 PetscCall(PetscViewerFlush(viewer)); 828 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 829 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 830 for (p = pStart; p < pEnd; ++p) { 831 PetscInt dof, off, c; 832 833 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 834 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 835 for (c = off; c < off+dof; ++c) { 836 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 837 } 838 } 839 PetscCall(PetscViewerFlush(viewer)); 840 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 841 if (coordSection && coordinates) { 842 CoordSystem cs = CS_CARTESIAN; 843 const PetscScalar *array, *arrayCell = NULL; 844 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 845 PetscMPIInt rank; 846 const char *name; 847 848 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 849 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 850 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 851 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 852 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 853 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 854 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 855 pStart = PetscMin(pvStart, pcStart); 856 pEnd = PetscMax(pvEnd, pcEnd); 857 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 859 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 860 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 861 862 PetscCall(VecGetArrayRead(coordinates, &array)); 863 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 864 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 865 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 866 for (p = pStart; p < pEnd; ++p) { 867 PetscInt dof, off; 868 869 if (p >= pvStart && p < pvEnd) { 870 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 871 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 872 if (dof) { 873 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 874 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 875 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 876 } 877 } 878 if (cdmCell && p >= pcStart && p < pcEnd) { 879 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 880 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 881 if (dof) { 882 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 883 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 884 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 885 } 886 } 887 } 888 PetscCall(PetscViewerFlush(viewer)); 889 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 890 PetscCall(VecRestoreArrayRead(coordinates, &array)); 891 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 892 } 893 PetscCall(DMGetNumLabels(dm, &numLabels)); 894 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 895 for (l = 0; l < numLabels; ++l) { 896 DMLabel label; 897 PetscBool isdepth; 898 const char *name; 899 900 PetscCall(DMGetLabelName(dm, l, &name)); 901 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 902 if (isdepth) continue; 903 PetscCall(DMGetLabel(dm, name, &label)); 904 PetscCall(DMLabelView(label, viewer)); 905 } 906 if (size > 1) { 907 PetscSF sf; 908 909 PetscCall(DMGetPointSF(dm, &sf)); 910 PetscCall(PetscSFView(sf, viewer)); 911 } 912 PetscCall(PetscViewerFlush(viewer)); 913 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 914 const char *name, *color; 915 const char *defcolors[3] = {"gray", "orange", "green"}; 916 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 917 char lname[PETSC_MAX_PATH_LEN]; 918 PetscReal scale = 2.0; 919 PetscReal tikzscale = 1.0; 920 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 921 double tcoords[3]; 922 PetscScalar *coords; 923 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 924 PetscMPIInt rank, size; 925 char **names, **colors, **lcolors; 926 PetscBool flg, lflg; 927 PetscBT wp = NULL; 928 PetscInt pEnd, pStart; 929 930 PetscCall(DMGetDimension(dm, &dim)); 931 PetscCall(DMPlexGetDepth(dm, &depth)); 932 PetscCall(DMGetNumLabels(dm, &numLabels)); 933 numLabels = PetscMax(numLabels, 10); 934 numColors = 10; 935 numLColors = 10; 936 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 937 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 938 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 939 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 940 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 941 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 942 n = 4; 943 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 944 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 945 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 946 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 947 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 948 if (!useLabels) numLabels = 0; 949 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 950 if (!useColors) { 951 numColors = 3; 952 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 953 } 954 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 955 if (!useColors) { 956 numLColors = 4; 957 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 958 } 959 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 960 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 961 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 962 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 963 if (depth < dim) plotEdges = PETSC_FALSE; 964 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 965 966 /* filter points with labelvalue != labeldefaultvalue */ 967 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 968 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 969 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 970 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 971 if (lflg) { 972 DMLabel lbl; 973 974 PetscCall(DMGetLabel(dm, lname, &lbl)); 975 if (lbl) { 976 PetscInt val, defval; 977 978 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 979 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 980 for (c = pStart; c < pEnd; c++) { 981 PetscInt *closure = NULL; 982 PetscInt closureSize; 983 984 PetscCall(DMLabelGetValue(lbl, c, &val)); 985 if (val == defval) continue; 986 987 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 988 for (p = 0; p < closureSize*2; p += 2) { 989 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 990 } 991 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 992 } 993 } 994 } 995 996 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 997 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 998 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 999 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1000 \\documentclass[tikz]{standalone}\n\n\ 1001 \\usepackage{pgflibraryshapes}\n\ 1002 \\usetikzlibrary{backgrounds}\n\ 1003 \\usetikzlibrary{arrows}\n\ 1004 \\begin{document}\n")); 1005 if (size > 1) { 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1007 for (p = 0; p < size; ++p) { 1008 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1010 } 1011 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1012 } 1013 if (drawHasse) { 1014 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1015 1016 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1028 } 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1030 1031 /* Plot vertices */ 1032 PetscCall(VecGetArray(coordinates, &coords)); 1033 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1034 for (v = vStart; v < vEnd; ++v) { 1035 PetscInt off, dof, d; 1036 PetscBool isLabeled = PETSC_FALSE; 1037 1038 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1039 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1040 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1041 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1042 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1043 for (d = 0; d < dof; ++d) { 1044 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1045 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1046 } 1047 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1048 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1049 for (d = 0; d < dof; ++d) { 1050 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1051 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1052 } 1053 if (drawHasse) color = colors[0%numColors]; 1054 else color = colors[rank%numColors]; 1055 for (l = 0; l < numLabels; ++l) { 1056 PetscInt val; 1057 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1058 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1059 } 1060 if (drawNumbers[0]) { 1061 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1062 } else if (drawColors[0]) { 1063 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1064 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1065 } 1066 PetscCall(VecRestoreArray(coordinates, &coords)); 1067 PetscCall(PetscViewerFlush(viewer)); 1068 /* Plot edges */ 1069 if (plotEdges) { 1070 PetscCall(VecGetArray(coordinates, &coords)); 1071 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1072 for (e = eStart; e < eEnd; ++e) { 1073 const PetscInt *cone; 1074 PetscInt coneSize, offA, offB, dof, d; 1075 1076 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1077 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1078 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1079 PetscCall(DMPlexGetCone(dm, e, &cone)); 1080 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1081 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1082 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1083 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1084 for (d = 0; d < dof; ++d) { 1085 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1086 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1087 } 1088 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1089 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1090 for (d = 0; d < dof; ++d) { 1091 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1093 } 1094 if (drawHasse) color = colors[1%numColors]; 1095 else color = colors[rank%numColors]; 1096 for (l = 0; l < numLabels; ++l) { 1097 PetscInt val; 1098 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1099 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1100 } 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1102 } 1103 PetscCall(VecRestoreArray(coordinates, &coords)); 1104 PetscCall(PetscViewerFlush(viewer)); 1105 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1106 } 1107 /* Plot cells */ 1108 if (dim == 3 || !drawNumbers[1]) { 1109 for (e = eStart; e < eEnd; ++e) { 1110 const PetscInt *cone; 1111 1112 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1113 color = colors[rank%numColors]; 1114 for (l = 0; l < numLabels; ++l) { 1115 PetscInt val; 1116 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1117 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1118 } 1119 PetscCall(DMPlexGetCone(dm, e, &cone)); 1120 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1121 } 1122 } else { 1123 DMPolytopeType ct; 1124 1125 /* Drawing a 2D polygon */ 1126 for (c = cStart; c < cEnd; ++c) { 1127 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1128 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1129 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1130 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1131 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1132 const PetscInt *cone; 1133 PetscInt coneSize, e; 1134 1135 PetscCall(DMPlexGetCone(dm, c, &cone)); 1136 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1137 for (e = 0; e < coneSize; ++e) { 1138 const PetscInt *econe; 1139 1140 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1141 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)); 1142 } 1143 } else { 1144 PetscInt *closure = NULL; 1145 PetscInt closureSize, Nv = 0, v; 1146 1147 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1148 for (p = 0; p < closureSize*2; p += 2) { 1149 const PetscInt point = closure[p]; 1150 1151 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1152 } 1153 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1154 for (v = 0; v <= Nv; ++v) { 1155 const PetscInt vertex = closure[v%Nv]; 1156 1157 if (v > 0) { 1158 if (plotEdges) { 1159 const PetscInt *edge; 1160 PetscInt endpoints[2], ne; 1161 1162 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1163 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1164 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1165 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1166 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1167 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1168 } 1169 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1170 } 1171 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1172 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 } 1174 } 1175 } 1176 PetscCall(VecGetArray(coordinates, &coords)); 1177 for (c = cStart; c < cEnd; ++c) { 1178 double ccoords[3] = {0.0, 0.0, 0.0}; 1179 PetscBool isLabeled = PETSC_FALSE; 1180 PetscInt *closure = NULL; 1181 PetscInt closureSize, dof, d, n = 0; 1182 1183 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1184 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1185 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1186 for (p = 0; p < closureSize*2; p += 2) { 1187 const PetscInt point = closure[p]; 1188 PetscInt off; 1189 1190 if ((point < vStart) || (point >= vEnd)) continue; 1191 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1192 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1193 for (d = 0; d < dof; ++d) { 1194 tcoords[d] = (double) (scale*PetscRealPart(coords[off+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 (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1199 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1200 ++n; 1201 } 1202 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1203 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1204 for (d = 0; d < dof; ++d) { 1205 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1207 } 1208 if (drawHasse) color = colors[depth%numColors]; 1209 else color = colors[rank%numColors]; 1210 for (l = 0; l < numLabels; ++l) { 1211 PetscInt val; 1212 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1213 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1214 } 1215 if (drawNumbers[dim]) { 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1217 } else if (drawColors[dim]) { 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1219 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1220 } 1221 PetscCall(VecRestoreArray(coordinates, &coords)); 1222 if (drawHasse) { 1223 color = colors[depth%numColors]; 1224 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1226 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1227 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1229 1230 color = colors[1%numColors]; 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1235 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1236 1237 color = colors[0%numColors]; 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1242 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1243 1244 for (p = pStart; p < pEnd; ++p) { 1245 const PetscInt *cone; 1246 PetscInt coneSize, cp; 1247 1248 PetscCall(DMPlexGetCone(dm, p, &cone)); 1249 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1250 for (cp = 0; cp < coneSize; ++cp) { 1251 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1252 } 1253 } 1254 } 1255 PetscCall(PetscViewerFlush(viewer)); 1256 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1258 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1259 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1260 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1261 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1262 PetscCall(PetscFree3(names, colors, lcolors)); 1263 PetscCall(PetscBTDestroy(&wp)); 1264 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1265 Vec cown,acown; 1266 VecScatter sct; 1267 ISLocalToGlobalMapping g2l; 1268 IS gid,acis; 1269 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1270 MPI_Group ggroup,ngroup; 1271 PetscScalar *array,nid; 1272 const PetscInt *idxs; 1273 PetscInt *idxs2,*start,*adjacency,*work; 1274 PetscInt64 lm[3],gm[3]; 1275 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1276 PetscMPIInt d1,d2,rank; 1277 1278 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1279 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1280 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1281 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1282 #endif 1283 if (ncomm != MPI_COMM_NULL) { 1284 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1285 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1286 d1 = 0; 1287 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1288 nid = d2; 1289 PetscCallMPI(MPI_Group_free(&ggroup)); 1290 PetscCallMPI(MPI_Group_free(&ngroup)); 1291 PetscCallMPI(MPI_Comm_free(&ncomm)); 1292 } else nid = 0.0; 1293 1294 /* Get connectivity */ 1295 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1296 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1297 1298 /* filter overlapped local cells */ 1299 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1300 PetscCall(ISGetIndices(gid,&idxs)); 1301 PetscCall(ISGetLocalSize(gid,&cum)); 1302 PetscCall(PetscMalloc1(cum,&idxs2)); 1303 for (c = cStart, cum = 0; c < cEnd; c++) { 1304 if (idxs[c-cStart] < 0) continue; 1305 idxs2[cum++] = idxs[c-cStart]; 1306 } 1307 PetscCall(ISRestoreIndices(gid,&idxs)); 1308 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1309 PetscCall(ISDestroy(&gid)); 1310 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1311 1312 /* support for node-aware cell locality */ 1313 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1314 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1315 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1316 PetscCall(VecGetArray(cown,&array)); 1317 for (c = 0; c < numVertices; c++) array[c] = nid; 1318 PetscCall(VecRestoreArray(cown,&array)); 1319 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1320 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1321 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1322 PetscCall(ISDestroy(&acis)); 1323 PetscCall(VecScatterDestroy(&sct)); 1324 PetscCall(VecDestroy(&cown)); 1325 1326 /* compute edgeCut */ 1327 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1328 PetscCall(PetscMalloc1(cum,&work)); 1329 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1330 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1331 PetscCall(ISDestroy(&gid)); 1332 PetscCall(VecGetArray(acown,&array)); 1333 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1334 PetscInt totl; 1335 1336 totl = start[c+1]-start[c]; 1337 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1338 for (i = 0; i < totl; i++) { 1339 if (work[i] < 0) { 1340 ect += 1; 1341 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1342 } 1343 } 1344 } 1345 PetscCall(PetscFree(work)); 1346 PetscCall(VecRestoreArray(acown,&array)); 1347 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1348 lm[1] = -numVertices; 1349 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1350 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1351 lm[0] = ect; /* edgeCut */ 1352 lm[1] = ectn; /* node-aware edgeCut */ 1353 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1354 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1355 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1356 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1357 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1358 #else 1359 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1360 #endif 1361 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1362 PetscCall(PetscFree(start)); 1363 PetscCall(PetscFree(adjacency)); 1364 PetscCall(VecDestroy(&acown)); 1365 } else { 1366 const char *name; 1367 PetscInt *sizes, *hybsizes, *ghostsizes; 1368 PetscInt locDepth, depth, cellHeight, dim, d; 1369 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1370 PetscInt numLabels, l, maxSize = 17; 1371 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1372 MPI_Comm comm; 1373 PetscMPIInt size, rank; 1374 1375 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1376 PetscCallMPI(MPI_Comm_size(comm, &size)); 1377 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1378 PetscCall(DMGetDimension(dm, &dim)); 1379 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1380 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1381 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1382 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1383 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1384 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1385 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1386 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1387 gcNum = gcEnd - gcStart; 1388 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1389 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1390 for (d = 0; d <= depth; d++) { 1391 PetscInt Nc[2] = {0, 0}, ict; 1392 1393 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1394 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1395 ict = ct0; 1396 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1397 ct0 = (DMPolytopeType) ict; 1398 for (p = pStart; p < pEnd; ++p) { 1399 DMPolytopeType ct; 1400 1401 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1402 if (ct == ct0) ++Nc[0]; 1403 else ++Nc[1]; 1404 } 1405 if (size < maxSize) { 1406 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1407 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1408 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1410 for (p = 0; p < size; ++p) { 1411 if (rank == 0) { 1412 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1413 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1414 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1415 } 1416 } 1417 } else { 1418 PetscInt locMinMax[2]; 1419 1420 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1421 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1422 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1423 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1424 if (d == depth) { 1425 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1426 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1427 } 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1430 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1431 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1432 } 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1434 } 1435 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1436 { 1437 const PetscReal *maxCell; 1438 const PetscReal *L; 1439 PetscBool localized; 1440 1441 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1442 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1443 if (L || localized) { 1444 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1445 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1446 if (L) { 1447 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1448 for (d = 0; d < dim; ++d) { 1449 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1450 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1451 } 1452 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1453 } 1454 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1455 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1456 } 1457 } 1458 PetscCall(DMGetNumLabels(dm, &numLabels)); 1459 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1460 for (l = 0; l < numLabels; ++l) { 1461 DMLabel label; 1462 const char *name; 1463 IS valueIS; 1464 const PetscInt *values; 1465 PetscInt numValues, v; 1466 1467 PetscCall(DMGetLabelName(dm, l, &name)); 1468 PetscCall(DMGetLabel(dm, name, &label)); 1469 PetscCall(DMLabelGetNumValues(label, &numValues)); 1470 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1471 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1472 PetscCall(ISGetIndices(valueIS, &values)); 1473 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1474 for (v = 0; v < numValues; ++v) { 1475 PetscInt size; 1476 1477 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1478 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1479 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1480 } 1481 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1482 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1483 PetscCall(ISRestoreIndices(valueIS, &values)); 1484 PetscCall(ISDestroy(&valueIS)); 1485 } 1486 { 1487 char **labelNames; 1488 PetscInt Nl = numLabels; 1489 PetscBool flg; 1490 1491 PetscCall(PetscMalloc1(Nl, &labelNames)); 1492 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1493 for (l = 0; l < Nl; ++l) { 1494 DMLabel label; 1495 1496 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1497 if (flg) { 1498 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1499 PetscCall(DMLabelView(label, viewer)); 1500 } 1501 PetscCall(PetscFree(labelNames[l])); 1502 } 1503 PetscCall(PetscFree(labelNames)); 1504 } 1505 /* If no fields are specified, people do not want to see adjacency */ 1506 if (dm->Nf) { 1507 PetscInt f; 1508 1509 for (f = 0; f < dm->Nf; ++f) { 1510 const char *name; 1511 1512 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1513 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1514 PetscCall(PetscViewerASCIIPushTab(viewer)); 1515 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1516 if (dm->fields[f].adjacency[0]) { 1517 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1518 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1519 } else { 1520 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1521 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1522 } 1523 PetscCall(PetscViewerASCIIPopTab(viewer)); 1524 } 1525 } 1526 PetscCall(DMGetCoarseDM(dm, &cdm)); 1527 if (cdm) { 1528 PetscCall(PetscViewerASCIIPushTab(viewer)); 1529 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1530 PetscCall(PetscViewerASCIIPopTab(viewer)); 1531 } 1532 } 1533 PetscFunctionReturn(0); 1534 } 1535 1536 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1537 { 1538 DMPolytopeType ct; 1539 PetscMPIInt rank; 1540 PetscInt cdim; 1541 1542 PetscFunctionBegin; 1543 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1544 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1545 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1546 switch (ct) { 1547 case DM_POLYTOPE_SEGMENT: 1548 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1549 switch (cdim) { 1550 case 1: 1551 { 1552 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1553 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1554 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1556 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1557 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1558 } 1559 break; 1560 case 2: 1561 { 1562 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1563 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1564 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1565 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 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)); 1568 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)); 1569 } 1570 break; 1571 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1572 } 1573 break; 1574 case DM_POLYTOPE_TRIANGLE: 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1582 break; 1583 case DM_POLYTOPE_QUADRILATERAL: 1584 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1585 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1586 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1587 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1588 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1589 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1590 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1591 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1592 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1598 } 1599 PetscFunctionReturn(0); 1600 } 1601 1602 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1603 { 1604 DMPolytopeType ct; 1605 PetscReal centroid[2] = {0., 0.}; 1606 PetscMPIInt rank; 1607 PetscInt fillColor, v, e, d; 1608 1609 PetscFunctionBegin; 1610 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1611 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1612 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1613 switch (ct) { 1614 case DM_POLYTOPE_TRIANGLE: 1615 { 1616 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1617 1618 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1619 for (e = 0; e < 3; ++e) { 1620 refCoords[0] = refVertices[e*2+0]; 1621 refCoords[1] = refVertices[e*2+1]; 1622 for (d = 1; d <= edgeDiv; ++d) { 1623 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1624 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1625 } 1626 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1627 for (d = 0; d < edgeDiv; ++d) { 1628 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)); 1629 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1630 } 1631 } 1632 } 1633 break; 1634 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1635 } 1636 PetscFunctionReturn(0); 1637 } 1638 1639 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1640 { 1641 PetscDraw draw; 1642 DM cdm; 1643 PetscSection coordSection; 1644 Vec coordinates; 1645 const PetscScalar *coords; 1646 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1647 PetscReal *refCoords, *edgeCoords; 1648 PetscBool isnull, drawAffine = PETSC_TRUE; 1649 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1650 1651 PetscFunctionBegin; 1652 PetscCall(DMGetCoordinateDim(dm, &dim)); 1653 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1654 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1655 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1656 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1657 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1658 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1659 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1660 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1661 1662 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1663 PetscCall(PetscDrawIsNull(draw, &isnull)); 1664 if (isnull) PetscFunctionReturn(0); 1665 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1666 1667 PetscCall(VecGetLocalSize(coordinates, &N)); 1668 PetscCall(VecGetArrayRead(coordinates, &coords)); 1669 for (c = 0; c < N; c += dim) { 1670 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1671 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1672 } 1673 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1674 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1675 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1676 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1677 PetscCall(PetscDrawClear(draw)); 1678 1679 for (c = cStart; c < cEnd; ++c) { 1680 PetscScalar *coords = NULL; 1681 PetscInt numCoords; 1682 1683 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1684 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1685 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1686 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1687 } 1688 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1689 PetscCall(PetscDrawFlush(draw)); 1690 PetscCall(PetscDrawPause(draw)); 1691 PetscCall(PetscDrawSave(draw)); 1692 PetscFunctionReturn(0); 1693 } 1694 1695 #if defined(PETSC_HAVE_EXODUSII) 1696 #include <exodusII.h> 1697 #include <petscviewerexodusii.h> 1698 #endif 1699 1700 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1701 { 1702 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1703 char name[PETSC_MAX_PATH_LEN]; 1704 1705 PetscFunctionBegin; 1706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1707 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1708 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1709 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1710 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1711 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1712 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1713 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1714 if (iascii) { 1715 PetscViewerFormat format; 1716 PetscCall(PetscViewerGetFormat(viewer, &format)); 1717 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1718 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1719 } else if (ishdf5) { 1720 #if defined(PETSC_HAVE_HDF5) 1721 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1722 #else 1723 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1724 #endif 1725 } else if (isvtk) { 1726 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1727 } else if (isdraw) { 1728 PetscCall(DMPlexView_Draw(dm, viewer)); 1729 } else if (isglvis) { 1730 PetscCall(DMPlexView_GLVis(dm, viewer)); 1731 #if defined(PETSC_HAVE_EXODUSII) 1732 } else if (isexodus) { 1733 /* 1734 exodusII requires that all sets be part of exactly one cell set. 1735 If the dm does not have a "Cell Sets" label defined, we create one 1736 with ID 1, containig all cells. 1737 Note that if the Cell Sets label is defined but does not cover all cells, 1738 we may still have a problem. This should probably be checked here or in the viewer; 1739 */ 1740 PetscInt numCS; 1741 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1742 if (!numCS) { 1743 PetscInt cStart, cEnd, c; 1744 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1745 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1746 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1747 } 1748 PetscCall(DMView_PlexExodusII(dm, viewer)); 1749 #endif 1750 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1751 1752 /* Optionally view the partition */ 1753 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1754 if (flg) { 1755 Vec ranks; 1756 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1757 PetscCall(VecView(ranks, viewer)); 1758 PetscCall(VecDestroy(&ranks)); 1759 } 1760 /* Optionally view a label */ 1761 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1762 if (flg) { 1763 DMLabel label; 1764 Vec val; 1765 1766 PetscCall(DMGetLabel(dm, name, &label)); 1767 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1768 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1769 PetscCall(VecView(val, viewer)); 1770 PetscCall(VecDestroy(&val)); 1771 } 1772 PetscFunctionReturn(0); 1773 } 1774 1775 /*@ 1776 DMPlexTopologyView - Saves a DMPlex topology into a file 1777 1778 Collective on DM 1779 1780 Input Parameters: 1781 + dm - The DM whose topology is to be saved 1782 - viewer - The PetscViewer for saving 1783 1784 Level: advanced 1785 1786 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1787 @*/ 1788 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1789 { 1790 PetscBool ishdf5; 1791 1792 PetscFunctionBegin; 1793 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1794 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1795 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1796 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1797 if (ishdf5) { 1798 #if defined(PETSC_HAVE_HDF5) 1799 PetscViewerFormat format; 1800 PetscCall(PetscViewerGetFormat(viewer, &format)); 1801 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1802 IS globalPointNumbering; 1803 1804 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1805 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1806 PetscCall(ISDestroy(&globalPointNumbering)); 1807 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1808 #else 1809 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1810 #endif 1811 } 1812 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1813 PetscFunctionReturn(0); 1814 } 1815 1816 /*@ 1817 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1818 1819 Collective on DM 1820 1821 Input Parameters: 1822 + dm - The DM whose coordinates are to be saved 1823 - viewer - The PetscViewer for saving 1824 1825 Level: advanced 1826 1827 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1828 @*/ 1829 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1830 { 1831 PetscBool ishdf5; 1832 1833 PetscFunctionBegin; 1834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1835 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1836 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1837 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1838 if (ishdf5) { 1839 #if defined(PETSC_HAVE_HDF5) 1840 PetscViewerFormat format; 1841 PetscCall(PetscViewerGetFormat(viewer, &format)); 1842 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1843 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1844 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1845 #else 1846 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1847 #endif 1848 } 1849 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1850 PetscFunctionReturn(0); 1851 } 1852 1853 /*@ 1854 DMPlexLabelsView - Saves DMPlex labels into a file 1855 1856 Collective on DM 1857 1858 Input Parameters: 1859 + dm - The DM whose labels are to be saved 1860 - viewer - The PetscViewer for saving 1861 1862 Level: advanced 1863 1864 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1865 @*/ 1866 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1867 { 1868 PetscBool ishdf5; 1869 1870 PetscFunctionBegin; 1871 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1872 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1873 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1874 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1875 if (ishdf5) { 1876 #if defined(PETSC_HAVE_HDF5) 1877 IS globalPointNumbering; 1878 PetscViewerFormat format; 1879 1880 PetscCall(PetscViewerGetFormat(viewer, &format)); 1881 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1882 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1883 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1884 PetscCall(ISDestroy(&globalPointNumbering)); 1885 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1886 #else 1887 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1888 #endif 1889 } 1890 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1891 PetscFunctionReturn(0); 1892 } 1893 1894 /*@ 1895 DMPlexSectionView - Saves a section associated with a DMPlex 1896 1897 Collective on DM 1898 1899 Input Parameters: 1900 + dm - The DM that contains the topology on which the section to be saved is defined 1901 . viewer - The PetscViewer for saving 1902 - sectiondm - The DM that contains the section to be saved 1903 1904 Level: advanced 1905 1906 Notes: 1907 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. 1908 1909 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. 1910 1911 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1912 @*/ 1913 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1914 { 1915 PetscBool ishdf5; 1916 1917 PetscFunctionBegin; 1918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1919 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1920 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1921 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1922 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1923 if (ishdf5) { 1924 #if defined(PETSC_HAVE_HDF5) 1925 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1926 #else 1927 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1928 #endif 1929 } 1930 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1931 PetscFunctionReturn(0); 1932 } 1933 1934 /*@ 1935 DMPlexGlobalVectorView - Saves a global vector 1936 1937 Collective on DM 1938 1939 Input Parameters: 1940 + dm - The DM that represents the topology 1941 . viewer - The PetscViewer to save data with 1942 . sectiondm - The DM that contains the global section on which vec is defined 1943 - vec - The global vector to be saved 1944 1945 Level: advanced 1946 1947 Notes: 1948 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. 1949 1950 Typical calling sequence 1951 $ DMCreate(PETSC_COMM_WORLD, &dm); 1952 $ DMSetType(dm, DMPLEX); 1953 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1954 $ DMClone(dm, §iondm); 1955 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1956 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1957 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1958 $ PetscSectionSetChart(section, pStart, pEnd); 1959 $ PetscSectionSetUp(section); 1960 $ DMSetLocalSection(sectiondm, section); 1961 $ PetscSectionDestroy(§ion); 1962 $ DMGetGlobalVector(sectiondm, &vec); 1963 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1964 $ DMPlexTopologyView(dm, viewer); 1965 $ DMPlexSectionView(dm, viewer, sectiondm); 1966 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1967 $ DMRestoreGlobalVector(sectiondm, &vec); 1968 $ DMDestroy(§iondm); 1969 $ DMDestroy(&dm); 1970 1971 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1972 @*/ 1973 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1974 { 1975 PetscBool ishdf5; 1976 1977 PetscFunctionBegin; 1978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1979 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1980 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1981 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1982 /* Check consistency */ 1983 { 1984 PetscSection section; 1985 PetscBool includesConstraints; 1986 PetscInt m, m1; 1987 1988 PetscCall(VecGetLocalSize(vec, &m1)); 1989 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1990 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1991 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1992 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1993 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1994 } 1995 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1996 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1997 if (ishdf5) { 1998 #if defined(PETSC_HAVE_HDF5) 1999 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2000 #else 2001 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2002 #endif 2003 } 2004 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2005 PetscFunctionReturn(0); 2006 } 2007 2008 /*@ 2009 DMPlexLocalVectorView - Saves a local vector 2010 2011 Collective on DM 2012 2013 Input Parameters: 2014 + dm - The DM that represents the topology 2015 . viewer - The PetscViewer to save data with 2016 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2017 - vec - The local vector to be saved 2018 2019 Level: advanced 2020 2021 Notes: 2022 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. 2023 2024 Typical calling sequence 2025 $ DMCreate(PETSC_COMM_WORLD, &dm); 2026 $ DMSetType(dm, DMPLEX); 2027 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2028 $ DMClone(dm, §iondm); 2029 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2030 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2031 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2032 $ PetscSectionSetChart(section, pStart, pEnd); 2033 $ PetscSectionSetUp(section); 2034 $ DMSetLocalSection(sectiondm, section); 2035 $ DMGetLocalVector(sectiondm, &vec); 2036 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2037 $ DMPlexTopologyView(dm, viewer); 2038 $ DMPlexSectionView(dm, viewer, sectiondm); 2039 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2040 $ DMRestoreLocalVector(sectiondm, &vec); 2041 $ DMDestroy(§iondm); 2042 $ DMDestroy(&dm); 2043 2044 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2045 @*/ 2046 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2047 { 2048 PetscBool ishdf5; 2049 2050 PetscFunctionBegin; 2051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2052 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2053 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2054 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2055 /* Check consistency */ 2056 { 2057 PetscSection section; 2058 PetscBool includesConstraints; 2059 PetscInt m, m1; 2060 2061 PetscCall(VecGetLocalSize(vec, &m1)); 2062 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2063 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2064 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2065 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2066 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2067 } 2068 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2069 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2070 if (ishdf5) { 2071 #if defined(PETSC_HAVE_HDF5) 2072 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2073 #else 2074 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2075 #endif 2076 } 2077 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2078 PetscFunctionReturn(0); 2079 } 2080 2081 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2082 { 2083 PetscBool ishdf5; 2084 2085 PetscFunctionBegin; 2086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2087 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2088 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2089 if (ishdf5) { 2090 #if defined(PETSC_HAVE_HDF5) 2091 PetscViewerFormat format; 2092 PetscCall(PetscViewerGetFormat(viewer, &format)); 2093 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2094 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2095 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2096 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2097 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2098 PetscFunctionReturn(0); 2099 #else 2100 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2101 #endif 2102 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2103 } 2104 2105 /*@ 2106 DMPlexTopologyLoad - Loads a topology into a DMPlex 2107 2108 Collective on DM 2109 2110 Input Parameters: 2111 + dm - The DM into which the topology is loaded 2112 - viewer - The PetscViewer for the saved topology 2113 2114 Output Parameters: 2115 . 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 2116 2117 Level: advanced 2118 2119 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2120 @*/ 2121 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2122 { 2123 PetscBool ishdf5; 2124 2125 PetscFunctionBegin; 2126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2127 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2128 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2129 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2130 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2131 if (ishdf5) { 2132 #if defined(PETSC_HAVE_HDF5) 2133 PetscViewerFormat format; 2134 PetscCall(PetscViewerGetFormat(viewer, &format)); 2135 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2136 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2137 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2138 #else 2139 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2140 #endif 2141 } 2142 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2143 PetscFunctionReturn(0); 2144 } 2145 2146 /*@ 2147 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2148 2149 Collective on DM 2150 2151 Input Parameters: 2152 + dm - The DM into which the coordinates are loaded 2153 . viewer - The PetscViewer for the saved coordinates 2154 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2155 2156 Level: advanced 2157 2158 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2159 @*/ 2160 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2161 { 2162 PetscBool ishdf5; 2163 2164 PetscFunctionBegin; 2165 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2166 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2167 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2168 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2169 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2170 if (ishdf5) { 2171 #if defined(PETSC_HAVE_HDF5) 2172 PetscViewerFormat format; 2173 PetscCall(PetscViewerGetFormat(viewer, &format)); 2174 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2175 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2176 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2177 #else 2178 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2179 #endif 2180 } 2181 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2182 PetscFunctionReturn(0); 2183 } 2184 2185 /*@ 2186 DMPlexLabelsLoad - Loads labels into a DMPlex 2187 2188 Collective on DM 2189 2190 Input Parameters: 2191 + dm - The DM into which the labels are loaded 2192 . viewer - The PetscViewer for the saved labels 2193 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2194 2195 Level: advanced 2196 2197 Notes: 2198 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2199 2200 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2201 @*/ 2202 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2203 { 2204 PetscBool ishdf5; 2205 2206 PetscFunctionBegin; 2207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2208 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2209 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2210 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2211 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2212 if (ishdf5) { 2213 #if defined(PETSC_HAVE_HDF5) 2214 PetscViewerFormat format; 2215 2216 PetscCall(PetscViewerGetFormat(viewer, &format)); 2217 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2218 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2219 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2220 #else 2221 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2222 #endif 2223 } 2224 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2225 PetscFunctionReturn(0); 2226 } 2227 2228 /*@ 2229 DMPlexSectionLoad - Loads section into a DMPlex 2230 2231 Collective on DM 2232 2233 Input Parameters: 2234 + dm - The DM that represents the topology 2235 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2236 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2237 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2238 2239 Output Parameters 2240 + 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) 2241 - 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) 2242 2243 Level: advanced 2244 2245 Notes: 2246 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. 2247 2248 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. 2249 2250 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. 2251 2252 Example using 2 processes: 2253 $ NX (number of points on dm): 4 2254 $ sectionA : the on-disk section 2255 $ vecA : a vector associated with sectionA 2256 $ sectionB : sectiondm's local section constructed in this function 2257 $ vecB (local) : a vector associated with sectiondm's local section 2258 $ vecB (global) : a vector associated with sectiondm's global section 2259 $ 2260 $ rank 0 rank 1 2261 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2262 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2263 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2264 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2265 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2266 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2267 $ sectionB->atlasDof : 1 0 1 | 1 3 2268 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2269 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2270 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2271 $ 2272 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2273 2274 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2275 @*/ 2276 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2277 { 2278 PetscBool ishdf5; 2279 2280 PetscFunctionBegin; 2281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2282 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2283 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2284 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2285 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2286 if (localDofSF) PetscValidPointer(localDofSF, 6); 2287 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2288 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2289 if (ishdf5) { 2290 #if defined(PETSC_HAVE_HDF5) 2291 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2292 #else 2293 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2294 #endif 2295 } 2296 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2297 PetscFunctionReturn(0); 2298 } 2299 2300 /*@ 2301 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2302 2303 Collective on DM 2304 2305 Input Parameters: 2306 + dm - The DM that represents the topology 2307 . viewer - The PetscViewer that represents the on-disk vector data 2308 . sectiondm - The DM that contains the global section on which vec is defined 2309 . sf - The SF that migrates the on-disk vector data into vec 2310 - vec - The global vector to set values of 2311 2312 Level: advanced 2313 2314 Notes: 2315 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. 2316 2317 Typical calling sequence 2318 $ DMCreate(PETSC_COMM_WORLD, &dm); 2319 $ DMSetType(dm, DMPLEX); 2320 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2321 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2322 $ DMClone(dm, §iondm); 2323 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2324 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2325 $ DMGetGlobalVector(sectiondm, &vec); 2326 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2327 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2328 $ DMRestoreGlobalVector(sectiondm, &vec); 2329 $ PetscSFDestroy(&gsf); 2330 $ PetscSFDestroy(&sfX); 2331 $ DMDestroy(§iondm); 2332 $ DMDestroy(&dm); 2333 2334 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2335 @*/ 2336 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2345 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2346 /* Check consistency */ 2347 { 2348 PetscSection section; 2349 PetscBool includesConstraints; 2350 PetscInt m, m1; 2351 2352 PetscCall(VecGetLocalSize(vec, &m1)); 2353 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2354 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2355 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2356 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2357 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2358 } 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2364 #else 2365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2366 #endif 2367 } 2368 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2369 PetscFunctionReturn(0); 2370 } 2371 2372 /*@ 2373 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2374 2375 Collective on DM 2376 2377 Input Parameters: 2378 + dm - The DM that represents the topology 2379 . viewer - The PetscViewer that represents the on-disk vector data 2380 . sectiondm - The DM that contains the local section on which vec is defined 2381 . sf - The SF that migrates the on-disk vector data into vec 2382 - vec - The local vector to set values of 2383 2384 Level: advanced 2385 2386 Notes: 2387 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. 2388 2389 Typical calling sequence 2390 $ DMCreate(PETSC_COMM_WORLD, &dm); 2391 $ DMSetType(dm, DMPLEX); 2392 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2393 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2394 $ DMClone(dm, §iondm); 2395 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2397 $ DMGetLocalVector(sectiondm, &vec); 2398 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2399 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2400 $ DMRestoreLocalVector(sectiondm, &vec); 2401 $ PetscSFDestroy(&lsf); 2402 $ PetscSFDestroy(&sfX); 2403 $ DMDestroy(§iondm); 2404 $ DMDestroy(&dm); 2405 2406 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2409 { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2441 PetscFunctionReturn(0); 2442 } 2443 2444 PetscErrorCode DMDestroy_Plex(DM dm) 2445 { 2446 DM_Plex *mesh = (DM_Plex*) dm->data; 2447 2448 PetscFunctionBegin; 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2461 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2462 if (--mesh->refct > 0) PetscFunctionReturn(0); 2463 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2464 PetscCall(PetscFree(mesh->cones)); 2465 PetscCall(PetscFree(mesh->coneOrientations)); 2466 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2467 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2468 PetscCall(PetscFree(mesh->supports)); 2469 PetscCall(PetscFree(mesh->facesTmp)); 2470 PetscCall(PetscFree(mesh->tetgenOpts)); 2471 PetscCall(PetscFree(mesh->triangleOpts)); 2472 PetscCall(PetscFree(mesh->transformType)); 2473 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2474 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2475 PetscCall(ISDestroy(&mesh->subpointIS)); 2476 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2477 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2478 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2479 PetscCall(ISDestroy(&mesh->anchorIS)); 2480 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2481 PetscCall(PetscFree(mesh->parents)); 2482 PetscCall(PetscFree(mesh->childIDs)); 2483 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2484 PetscCall(PetscFree(mesh->children)); 2485 PetscCall(DMDestroy(&mesh->referenceTree)); 2486 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2487 PetscCall(PetscFree(mesh->neighbors)); 2488 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2489 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2490 PetscCall(PetscFree(mesh)); 2491 PetscFunctionReturn(0); 2492 } 2493 2494 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2495 { 2496 PetscSection sectionGlobal; 2497 PetscInt bs = -1, mbs; 2498 PetscInt localSize, localStart = 0; 2499 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2500 MatType mtype; 2501 ISLocalToGlobalMapping ltog; 2502 2503 PetscFunctionBegin; 2504 PetscCall(MatInitializePackage()); 2505 mtype = dm->mattype; 2506 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2507 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2508 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2509 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2510 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2511 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2512 PetscCall(MatSetType(*J, mtype)); 2513 PetscCall(MatSetFromOptions(*J)); 2514 PetscCall(MatGetBlockSize(*J, &mbs)); 2515 if (mbs > 1) bs = mbs; 2516 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2517 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2522 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2523 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2524 if (!isShell) { 2525 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2526 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2527 PetscInt pStart, pEnd, p, dof, cdof; 2528 2529 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2530 2531 PetscCall(PetscCalloc1(localSize, &pblocks)); 2532 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2533 for (p = pStart; p < pEnd; ++p) { 2534 PetscInt bdof, offset; 2535 2536 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2537 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2538 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2539 for (PetscInt i=0; i < dof - cdof; i++) 2540 pblocks[offset - localStart + i] = dof - cdof; 2541 dof = dof < 0 ? -(dof+1) : dof; 2542 bdof = cdof && (dof-cdof) ? 1 : dof; 2543 if (dof) { 2544 if (bs < 0) {bs = bdof;} 2545 else if (bs != bdof) {bs = 1;} 2546 } 2547 } 2548 /* Must have same blocksize on all procs (some might have no points) */ 2549 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2550 bsLocal[1] = bs; 2551 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2552 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2553 else bs = bsMinMax[0]; 2554 bs = PetscMax(1,bs); 2555 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2556 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2557 PetscCall(MatSetBlockSize(*J, bs)); 2558 PetscCall(MatSetUp(*J)); 2559 } else { 2560 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2561 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2562 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2563 } 2564 { // Consolidate blocks 2565 PetscInt nblocks = 0; 2566 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2567 if (pblocks[i] == 0) continue; 2568 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2569 for (PetscInt j=1; j<pblocks[i]; j++) { 2570 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]); 2571 } 2572 } 2573 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2574 } 2575 PetscCall(PetscFree(pblocks)); 2576 } 2577 PetscCall(MatSetDM(*J, dm)); 2578 PetscFunctionReturn(0); 2579 } 2580 2581 /*@ 2582 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2583 2584 Not collective 2585 2586 Input Parameter: 2587 . mesh - The DMPlex 2588 2589 Output Parameters: 2590 . subsection - The subdomain section 2591 2592 Level: developer 2593 2594 .seealso: 2595 @*/ 2596 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2597 { 2598 DM_Plex *mesh = (DM_Plex*) dm->data; 2599 2600 PetscFunctionBegin; 2601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2602 if (!mesh->subdomainSection) { 2603 PetscSection section; 2604 PetscSF sf; 2605 2606 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2607 PetscCall(DMGetLocalSection(dm,§ion)); 2608 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2609 PetscCall(PetscSFDestroy(&sf)); 2610 } 2611 *subsection = mesh->subdomainSection; 2612 PetscFunctionReturn(0); 2613 } 2614 2615 /*@ 2616 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2617 2618 Not collective 2619 2620 Input Parameter: 2621 . mesh - The DMPlex 2622 2623 Output Parameters: 2624 + pStart - The first mesh point 2625 - pEnd - The upper bound for mesh points 2626 2627 Level: beginner 2628 2629 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2630 @*/ 2631 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2632 { 2633 DM_Plex *mesh = (DM_Plex*) dm->data; 2634 2635 PetscFunctionBegin; 2636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2637 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2638 PetscFunctionReturn(0); 2639 } 2640 2641 /*@ 2642 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2643 2644 Not collective 2645 2646 Input Parameters: 2647 + mesh - The DMPlex 2648 . pStart - The first mesh point 2649 - pEnd - The upper bound for mesh points 2650 2651 Output Parameters: 2652 2653 Level: beginner 2654 2655 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2656 @*/ 2657 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2658 { 2659 DM_Plex *mesh = (DM_Plex*) dm->data; 2660 2661 PetscFunctionBegin; 2662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2663 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2664 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2665 PetscFunctionReturn(0); 2666 } 2667 2668 /*@ 2669 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2670 2671 Not collective 2672 2673 Input Parameters: 2674 + mesh - The DMPlex 2675 - p - The point, which must lie in the chart set with DMPlexSetChart() 2676 2677 Output Parameter: 2678 . size - The cone size for point p 2679 2680 Level: beginner 2681 2682 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2683 @*/ 2684 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2685 { 2686 DM_Plex *mesh = (DM_Plex*) dm->data; 2687 2688 PetscFunctionBegin; 2689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2690 PetscValidIntPointer(size, 3); 2691 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2692 PetscFunctionReturn(0); 2693 } 2694 2695 /*@ 2696 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2697 2698 Not collective 2699 2700 Input Parameters: 2701 + mesh - The DMPlex 2702 . p - The point, which must lie in the chart set with DMPlexSetChart() 2703 - size - The cone size for point p 2704 2705 Output Parameter: 2706 2707 Note: 2708 This should be called after DMPlexSetChart(). 2709 2710 Level: beginner 2711 2712 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2713 @*/ 2714 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2715 { 2716 DM_Plex *mesh = (DM_Plex*) dm->data; 2717 2718 PetscFunctionBegin; 2719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2720 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2721 PetscFunctionReturn(0); 2722 } 2723 2724 /*@ 2725 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2726 2727 Not collective 2728 2729 Input Parameters: 2730 + mesh - The DMPlex 2731 . p - The point, which must lie in the chart set with DMPlexSetChart() 2732 - size - The additional cone size for point p 2733 2734 Output Parameter: 2735 2736 Note: 2737 This should be called after DMPlexSetChart(). 2738 2739 Level: beginner 2740 2741 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2742 @*/ 2743 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2744 { 2745 DM_Plex *mesh = (DM_Plex*) dm->data; 2746 PetscFunctionBegin; 2747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2748 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2749 PetscFunctionReturn(0); 2750 } 2751 2752 /*@C 2753 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2754 2755 Not collective 2756 2757 Input Parameters: 2758 + dm - The DMPlex 2759 - p - The point, which must lie in the chart set with DMPlexSetChart() 2760 2761 Output Parameter: 2762 . cone - An array of points which are on the in-edges for point p 2763 2764 Level: beginner 2765 2766 Fortran Notes: 2767 Since it returns an array, this routine is only available in Fortran 90, and you must 2768 include petsc.h90 in your code. 2769 You must also call DMPlexRestoreCone() after you finish using the returned array. 2770 DMPlexRestoreCone() is not needed/available in C. 2771 2772 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2773 @*/ 2774 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2775 { 2776 DM_Plex *mesh = (DM_Plex*) dm->data; 2777 PetscInt off; 2778 2779 PetscFunctionBegin; 2780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2781 PetscValidPointer(cone, 3); 2782 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2783 *cone = &mesh->cones[off]; 2784 PetscFunctionReturn(0); 2785 } 2786 2787 /*@C 2788 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2789 2790 Not collective 2791 2792 Input Parameters: 2793 + dm - The DMPlex 2794 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2795 2796 Output Parameters: 2797 + pConesSection - PetscSection describing the layout of pCones 2798 - pCones - An array of points which are on the in-edges for the point set p 2799 2800 Level: intermediate 2801 2802 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2803 @*/ 2804 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2805 { 2806 PetscSection cs, newcs; 2807 PetscInt *cones; 2808 PetscInt *newarr=NULL; 2809 PetscInt n; 2810 2811 PetscFunctionBegin; 2812 PetscCall(DMPlexGetCones(dm, &cones)); 2813 PetscCall(DMPlexGetConeSection(dm, &cs)); 2814 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2815 if (pConesSection) *pConesSection = newcs; 2816 if (pCones) { 2817 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2818 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2819 } 2820 PetscFunctionReturn(0); 2821 } 2822 2823 /*@ 2824 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2825 2826 Not collective 2827 2828 Input Parameters: 2829 + dm - The DMPlex 2830 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2831 2832 Output Parameter: 2833 . expandedPoints - An array of vertices recursively expanded from input points 2834 2835 Level: advanced 2836 2837 Notes: 2838 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2839 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2840 2841 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2842 @*/ 2843 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2844 { 2845 IS *expandedPointsAll; 2846 PetscInt depth; 2847 2848 PetscFunctionBegin; 2849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2850 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2851 PetscValidPointer(expandedPoints, 3); 2852 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2853 *expandedPoints = expandedPointsAll[0]; 2854 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2855 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2856 PetscFunctionReturn(0); 2857 } 2858 2859 /*@ 2860 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). 2861 2862 Not collective 2863 2864 Input Parameters: 2865 + dm - The DMPlex 2866 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2867 2868 Output Parameters: 2869 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2870 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2871 - sections - (optional) An array of sections which describe mappings from points to their cone points 2872 2873 Level: advanced 2874 2875 Notes: 2876 Like DMPlexGetConeTuple() but recursive. 2877 2878 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. 2879 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2880 2881 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: 2882 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2883 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2884 2885 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2886 @*/ 2887 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2888 { 2889 const PetscInt *arr0=NULL, *cone=NULL; 2890 PetscInt *arr=NULL, *newarr=NULL; 2891 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2892 IS *expandedPoints_; 2893 PetscSection *sections_; 2894 2895 PetscFunctionBegin; 2896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2897 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2898 if (depth) PetscValidIntPointer(depth, 3); 2899 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2900 if (sections) PetscValidPointer(sections, 5); 2901 PetscCall(ISGetLocalSize(points, &n)); 2902 PetscCall(ISGetIndices(points, &arr0)); 2903 PetscCall(DMPlexGetDepth(dm, &depth_)); 2904 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2905 PetscCall(PetscCalloc1(depth_, §ions_)); 2906 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2907 for (d=depth_-1; d>=0; d--) { 2908 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2909 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2910 for (i=0; i<n; i++) { 2911 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2912 if (arr[i] >= start && arr[i] < end) { 2913 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2914 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2915 } else { 2916 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2917 } 2918 } 2919 PetscCall(PetscSectionSetUp(sections_[d])); 2920 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2921 PetscCall(PetscMalloc1(newn, &newarr)); 2922 for (i=0; i<n; i++) { 2923 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2924 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2925 if (cn > 1) { 2926 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2927 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2928 } else { 2929 newarr[co] = arr[i]; 2930 } 2931 } 2932 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2933 arr = newarr; 2934 n = newn; 2935 } 2936 PetscCall(ISRestoreIndices(points, &arr0)); 2937 *depth = depth_; 2938 if (expandedPoints) *expandedPoints = expandedPoints_; 2939 else { 2940 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2941 PetscCall(PetscFree(expandedPoints_)); 2942 } 2943 if (sections) *sections = sections_; 2944 else { 2945 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2946 PetscCall(PetscFree(sections_)); 2947 } 2948 PetscFunctionReturn(0); 2949 } 2950 2951 /*@ 2952 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2953 2954 Not collective 2955 2956 Input Parameters: 2957 + dm - The DMPlex 2958 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2959 2960 Output Parameters: 2961 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2962 . expandedPoints - (optional) An array of recursively expanded cones 2963 - sections - (optional) An array of sections which describe mappings from points to their cone points 2964 2965 Level: advanced 2966 2967 Notes: 2968 See DMPlexGetConeRecursive() for details. 2969 2970 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2971 @*/ 2972 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2973 { 2974 PetscInt d, depth_; 2975 2976 PetscFunctionBegin; 2977 PetscCall(DMPlexGetDepth(dm, &depth_)); 2978 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2979 if (depth) *depth = 0; 2980 if (expandedPoints) { 2981 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2982 PetscCall(PetscFree(*expandedPoints)); 2983 } 2984 if (sections) { 2985 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2986 PetscCall(PetscFree(*sections)); 2987 } 2988 PetscFunctionReturn(0); 2989 } 2990 2991 /*@ 2992 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 2993 2994 Not collective 2995 2996 Input Parameters: 2997 + mesh - The DMPlex 2998 . p - The point, which must lie in the chart set with DMPlexSetChart() 2999 - cone - An array of points which are on the in-edges for point p 3000 3001 Output Parameter: 3002 3003 Note: 3004 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3005 3006 Level: beginner 3007 3008 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3009 @*/ 3010 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3011 { 3012 DM_Plex *mesh = (DM_Plex*) dm->data; 3013 PetscInt pStart, pEnd; 3014 PetscInt dof, off, c; 3015 3016 PetscFunctionBegin; 3017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3018 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3019 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3020 if (dof) PetscValidIntPointer(cone, 3); 3021 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3022 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); 3023 for (c = 0; c < dof; ++c) { 3024 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); 3025 mesh->cones[off+c] = cone[c]; 3026 } 3027 PetscFunctionReturn(0); 3028 } 3029 3030 /*@C 3031 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3032 3033 Not collective 3034 3035 Input Parameters: 3036 + mesh - The DMPlex 3037 - p - The point, which must lie in the chart set with DMPlexSetChart() 3038 3039 Output Parameter: 3040 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3041 integer giving the prescription for cone traversal. 3042 3043 Level: beginner 3044 3045 Notes: 3046 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3047 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3048 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3049 with the identity. 3050 3051 Fortran Notes: 3052 Since it returns an array, this routine is only available in Fortran 90, and you must 3053 include petsc.h90 in your code. 3054 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3055 DMPlexRestoreConeOrientation() is not needed/available in C. 3056 3057 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3058 @*/ 3059 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3060 { 3061 DM_Plex *mesh = (DM_Plex*) dm->data; 3062 PetscInt off; 3063 3064 PetscFunctionBegin; 3065 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3066 if (PetscDefined(USE_DEBUG)) { 3067 PetscInt dof; 3068 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3069 if (dof) PetscValidPointer(coneOrientation, 3); 3070 } 3071 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3072 3073 *coneOrientation = &mesh->coneOrientations[off]; 3074 PetscFunctionReturn(0); 3075 } 3076 3077 /*@ 3078 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3079 3080 Not collective 3081 3082 Input Parameters: 3083 + mesh - The DMPlex 3084 . p - The point, which must lie in the chart set with DMPlexSetChart() 3085 - coneOrientation - An array of orientations 3086 Output Parameter: 3087 3088 Notes: 3089 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3090 3091 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3092 3093 Level: beginner 3094 3095 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3096 @*/ 3097 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3098 { 3099 DM_Plex *mesh = (DM_Plex*) dm->data; 3100 PetscInt pStart, pEnd; 3101 PetscInt dof, off, c; 3102 3103 PetscFunctionBegin; 3104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3105 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3106 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3107 if (dof) PetscValidIntPointer(coneOrientation, 3); 3108 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3109 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); 3110 for (c = 0; c < dof; ++c) { 3111 PetscInt cdof, o = coneOrientation[c]; 3112 3113 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3114 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); 3115 mesh->coneOrientations[off+c] = o; 3116 } 3117 PetscFunctionReturn(0); 3118 } 3119 3120 /*@ 3121 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3122 3123 Not collective 3124 3125 Input Parameters: 3126 + mesh - The DMPlex 3127 . p - The point, which must lie in the chart set with DMPlexSetChart() 3128 . conePos - The local index in the cone where the point should be put 3129 - conePoint - The mesh point to insert 3130 3131 Level: beginner 3132 3133 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3134 @*/ 3135 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3136 { 3137 DM_Plex *mesh = (DM_Plex*) dm->data; 3138 PetscInt pStart, pEnd; 3139 PetscInt dof, off; 3140 3141 PetscFunctionBegin; 3142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3143 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3144 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); 3145 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); 3146 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3147 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3148 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); 3149 mesh->cones[off+conePos] = conePoint; 3150 PetscFunctionReturn(0); 3151 } 3152 3153 /*@ 3154 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3155 3156 Not collective 3157 3158 Input Parameters: 3159 + mesh - The DMPlex 3160 . p - The point, which must lie in the chart set with DMPlexSetChart() 3161 . conePos - The local index in the cone where the point should be put 3162 - coneOrientation - The point orientation to insert 3163 3164 Level: beginner 3165 3166 Notes: 3167 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3168 3169 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3170 @*/ 3171 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3172 { 3173 DM_Plex *mesh = (DM_Plex*) dm->data; 3174 PetscInt pStart, pEnd; 3175 PetscInt dof, off; 3176 3177 PetscFunctionBegin; 3178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3179 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3180 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); 3181 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3182 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3183 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); 3184 mesh->coneOrientations[off+conePos] = coneOrientation; 3185 PetscFunctionReturn(0); 3186 } 3187 3188 /*@ 3189 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3190 3191 Not collective 3192 3193 Input Parameters: 3194 + mesh - The DMPlex 3195 - p - The point, which must lie in the chart set with DMPlexSetChart() 3196 3197 Output Parameter: 3198 . size - The support size for point p 3199 3200 Level: beginner 3201 3202 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3203 @*/ 3204 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3205 { 3206 DM_Plex *mesh = (DM_Plex*) dm->data; 3207 3208 PetscFunctionBegin; 3209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3210 PetscValidIntPointer(size, 3); 3211 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3212 PetscFunctionReturn(0); 3213 } 3214 3215 /*@ 3216 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3217 3218 Not collective 3219 3220 Input Parameters: 3221 + mesh - The DMPlex 3222 . p - The point, which must lie in the chart set with DMPlexSetChart() 3223 - size - The support size for point p 3224 3225 Output Parameter: 3226 3227 Note: 3228 This should be called after DMPlexSetChart(). 3229 3230 Level: beginner 3231 3232 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3233 @*/ 3234 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3235 { 3236 DM_Plex *mesh = (DM_Plex*) dm->data; 3237 3238 PetscFunctionBegin; 3239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3240 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3241 PetscFunctionReturn(0); 3242 } 3243 3244 /*@C 3245 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3246 3247 Not collective 3248 3249 Input Parameters: 3250 + mesh - The DMPlex 3251 - p - The point, which must lie in the chart set with DMPlexSetChart() 3252 3253 Output Parameter: 3254 . support - An array of points which are on the out-edges for point p 3255 3256 Level: beginner 3257 3258 Fortran Notes: 3259 Since it returns an array, this routine is only available in Fortran 90, and you must 3260 include petsc.h90 in your code. 3261 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3262 DMPlexRestoreSupport() is not needed/available in C. 3263 3264 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3265 @*/ 3266 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3267 { 3268 DM_Plex *mesh = (DM_Plex*) dm->data; 3269 PetscInt off; 3270 3271 PetscFunctionBegin; 3272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3273 PetscValidPointer(support, 3); 3274 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3275 *support = &mesh->supports[off]; 3276 PetscFunctionReturn(0); 3277 } 3278 3279 /*@ 3280 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3281 3282 Not collective 3283 3284 Input Parameters: 3285 + mesh - The DMPlex 3286 . p - The point, which must lie in the chart set with DMPlexSetChart() 3287 - support - An array of points which are on the out-edges for point p 3288 3289 Output Parameter: 3290 3291 Note: 3292 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3293 3294 Level: beginner 3295 3296 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3297 @*/ 3298 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3299 { 3300 DM_Plex *mesh = (DM_Plex*) dm->data; 3301 PetscInt pStart, pEnd; 3302 PetscInt dof, off, c; 3303 3304 PetscFunctionBegin; 3305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3306 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3307 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3308 if (dof) PetscValidIntPointer(support, 3); 3309 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3310 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); 3311 for (c = 0; c < dof; ++c) { 3312 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); 3313 mesh->supports[off+c] = support[c]; 3314 } 3315 PetscFunctionReturn(0); 3316 } 3317 3318 /*@ 3319 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3320 3321 Not collective 3322 3323 Input Parameters: 3324 + mesh - The DMPlex 3325 . p - The point, which must lie in the chart set with DMPlexSetChart() 3326 . supportPos - The local index in the cone where the point should be put 3327 - supportPoint - The mesh point to insert 3328 3329 Level: beginner 3330 3331 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3332 @*/ 3333 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3334 { 3335 DM_Plex *mesh = (DM_Plex*) dm->data; 3336 PetscInt pStart, pEnd; 3337 PetscInt dof, off; 3338 3339 PetscFunctionBegin; 3340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3341 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3342 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3343 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3344 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); 3345 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); 3346 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); 3347 mesh->supports[off+supportPos] = supportPoint; 3348 PetscFunctionReturn(0); 3349 } 3350 3351 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3352 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3353 { 3354 switch (ct) { 3355 case DM_POLYTOPE_SEGMENT: 3356 if (o == -1) return -2; 3357 break; 3358 case DM_POLYTOPE_TRIANGLE: 3359 if (o == -3) return -1; 3360 if (o == -2) return -3; 3361 if (o == -1) return -2; 3362 break; 3363 case DM_POLYTOPE_QUADRILATERAL: 3364 if (o == -4) return -2; 3365 if (o == -3) return -1; 3366 if (o == -2) return -4; 3367 if (o == -1) return -3; 3368 break; 3369 default: return o; 3370 } 3371 return o; 3372 } 3373 3374 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3375 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3376 { 3377 switch (ct) { 3378 case DM_POLYTOPE_SEGMENT: 3379 if ((o == -2) || (o == 1)) return -1; 3380 if (o == -1) return 0; 3381 break; 3382 case DM_POLYTOPE_TRIANGLE: 3383 if (o == -3) return -2; 3384 if (o == -2) return -1; 3385 if (o == -1) return -3; 3386 break; 3387 case DM_POLYTOPE_QUADRILATERAL: 3388 if (o == -4) return -2; 3389 if (o == -3) return -1; 3390 if (o == -2) return -4; 3391 if (o == -1) return -3; 3392 break; 3393 default: return o; 3394 } 3395 return o; 3396 } 3397 3398 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3399 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3400 { 3401 PetscInt pStart, pEnd, p; 3402 3403 PetscFunctionBegin; 3404 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3405 for (p = pStart; p < pEnd; ++p) { 3406 const PetscInt *cone, *ornt; 3407 PetscInt coneSize, c; 3408 3409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3410 PetscCall(DMPlexGetCone(dm, p, &cone)); 3411 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3412 for (c = 0; c < coneSize; ++c) { 3413 DMPolytopeType ct; 3414 const PetscInt o = ornt[c]; 3415 3416 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3417 switch (ct) { 3418 case DM_POLYTOPE_SEGMENT: 3419 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3420 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3421 break; 3422 case DM_POLYTOPE_TRIANGLE: 3423 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3424 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3425 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3426 break; 3427 case DM_POLYTOPE_QUADRILATERAL: 3428 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3429 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3430 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3431 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3432 break; 3433 default: break; 3434 } 3435 } 3436 } 3437 PetscFunctionReturn(0); 3438 } 3439 3440 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3441 { 3442 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3443 PetscInt *closure; 3444 const PetscInt *tmp = NULL, *tmpO = NULL; 3445 PetscInt off = 0, tmpSize, t; 3446 3447 PetscFunctionBeginHot; 3448 if (ornt) { 3449 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3450 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3451 } 3452 if (*points) { 3453 closure = *points; 3454 } else { 3455 PetscInt maxConeSize, maxSupportSize; 3456 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3457 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3458 } 3459 if (useCone) { 3460 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3461 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3462 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3463 } else { 3464 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3465 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3466 } 3467 if (ct == DM_POLYTOPE_UNKNOWN) { 3468 closure[off++] = p; 3469 closure[off++] = 0; 3470 for (t = 0; t < tmpSize; ++t) { 3471 closure[off++] = tmp[t]; 3472 closure[off++] = tmpO ? tmpO[t] : 0; 3473 } 3474 } else { 3475 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3476 3477 /* We assume that cells with a valid type have faces with a valid type */ 3478 closure[off++] = p; 3479 closure[off++] = ornt; 3480 for (t = 0; t < tmpSize; ++t) { 3481 DMPolytopeType ft; 3482 3483 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3484 closure[off++] = tmp[arr[t]]; 3485 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3486 } 3487 } 3488 if (numPoints) *numPoints = tmpSize+1; 3489 if (points) *points = closure; 3490 PetscFunctionReturn(0); 3491 } 3492 3493 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3494 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3495 { 3496 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3497 const PetscInt *cone, *ornt; 3498 PetscInt *pts, *closure = NULL; 3499 DMPolytopeType ft; 3500 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3501 PetscInt dim, coneSize, c, d, clSize, cl; 3502 3503 PetscFunctionBeginHot; 3504 PetscCall(DMGetDimension(dm, &dim)); 3505 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3506 PetscCall(DMPlexGetCone(dm, point, &cone)); 3507 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3508 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3509 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3510 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3511 maxSize = PetscMax(coneSeries, supportSeries); 3512 if (*points) {pts = *points;} 3513 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3514 c = 0; 3515 pts[c++] = point; 3516 pts[c++] = o; 3517 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3518 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3519 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3520 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3521 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3522 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3523 for (d = 2; d < coneSize; ++d) { 3524 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3525 pts[c++] = cone[arr[d*2+0]]; 3526 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3527 } 3528 if (dim >= 3) { 3529 for (d = 2; d < coneSize; ++d) { 3530 const PetscInt fpoint = cone[arr[d*2+0]]; 3531 const PetscInt *fcone, *fornt; 3532 PetscInt fconeSize, fc, i; 3533 3534 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3535 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3536 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3537 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3538 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3539 for (fc = 0; fc < fconeSize; ++fc) { 3540 const PetscInt cp = fcone[farr[fc*2+0]]; 3541 const PetscInt co = farr[fc*2+1]; 3542 3543 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3544 if (i == c) { 3545 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3546 pts[c++] = cp; 3547 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3548 } 3549 } 3550 } 3551 } 3552 *numPoints = c/2; 3553 *points = pts; 3554 PetscFunctionReturn(0); 3555 } 3556 3557 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3558 { 3559 DMPolytopeType ct; 3560 PetscInt *closure, *fifo; 3561 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3562 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3563 PetscInt depth, maxSize; 3564 3565 PetscFunctionBeginHot; 3566 PetscCall(DMPlexGetDepth(dm, &depth)); 3567 if (depth == 1) { 3568 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3569 PetscFunctionReturn(0); 3570 } 3571 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3572 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3573 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3574 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3575 PetscFunctionReturn(0); 3576 } 3577 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3578 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3579 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3580 maxSize = PetscMax(coneSeries, supportSeries); 3581 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3582 if (*points) {closure = *points;} 3583 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3584 closure[closureSize++] = p; 3585 closure[closureSize++] = ornt; 3586 fifo[fifoSize++] = p; 3587 fifo[fifoSize++] = ornt; 3588 fifo[fifoSize++] = ct; 3589 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3590 while (fifoSize - fifoStart) { 3591 const PetscInt q = fifo[fifoStart++]; 3592 const PetscInt o = fifo[fifoStart++]; 3593 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3594 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3595 const PetscInt *tmp, *tmpO; 3596 PetscInt tmpSize, t; 3597 3598 if (PetscDefined(USE_DEBUG)) { 3599 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3600 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); 3601 } 3602 if (useCone) { 3603 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3604 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3605 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3606 } else { 3607 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3608 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3609 tmpO = NULL; 3610 } 3611 for (t = 0; t < tmpSize; ++t) { 3612 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3613 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3614 const PetscInt cp = tmp[ip]; 3615 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3616 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3617 PetscInt c; 3618 3619 /* Check for duplicate */ 3620 for (c = 0; c < closureSize; c += 2) { 3621 if (closure[c] == cp) break; 3622 } 3623 if (c == closureSize) { 3624 closure[closureSize++] = cp; 3625 closure[closureSize++] = co; 3626 fifo[fifoSize++] = cp; 3627 fifo[fifoSize++] = co; 3628 fifo[fifoSize++] = ct; 3629 } 3630 } 3631 } 3632 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3633 if (numPoints) *numPoints = closureSize/2; 3634 if (points) *points = closure; 3635 PetscFunctionReturn(0); 3636 } 3637 3638 /*@C 3639 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3640 3641 Not collective 3642 3643 Input Parameters: 3644 + dm - The DMPlex 3645 . p - The mesh point 3646 - useCone - PETSC_TRUE for the closure, otherwise return the star 3647 3648 Input/Output Parameter: 3649 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3650 if NULL on input, internal storage will be returned, otherwise the provided array is used 3651 3652 Output Parameter: 3653 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3654 3655 Note: 3656 If using internal storage (points is NULL on input), each call overwrites the last output. 3657 3658 Fortran Notes: 3659 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3660 3661 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3662 3663 Level: beginner 3664 3665 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3666 @*/ 3667 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3668 { 3669 PetscFunctionBeginHot; 3670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3671 if (numPoints) PetscValidIntPointer(numPoints, 4); 3672 if (points) PetscValidPointer(points, 5); 3673 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3674 PetscFunctionReturn(0); 3675 } 3676 3677 /*@C 3678 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3679 3680 Not collective 3681 3682 Input Parameters: 3683 + dm - The DMPlex 3684 . p - The mesh point 3685 . useCone - PETSC_TRUE for the closure, otherwise return the star 3686 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3687 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3688 3689 Note: 3690 If not using internal storage (points is not NULL on input), this call is unnecessary 3691 3692 Fortran Notes: 3693 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3694 3695 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3696 3697 Level: beginner 3698 3699 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3700 @*/ 3701 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3702 { 3703 PetscFunctionBeginHot; 3704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3705 if (numPoints) *numPoints = 0; 3706 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3707 PetscFunctionReturn(0); 3708 } 3709 3710 /*@ 3711 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3712 3713 Not collective 3714 3715 Input Parameter: 3716 . mesh - The DMPlex 3717 3718 Output Parameters: 3719 + maxConeSize - The maximum number of in-edges 3720 - maxSupportSize - The maximum number of out-edges 3721 3722 Level: beginner 3723 3724 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3725 @*/ 3726 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3727 { 3728 DM_Plex *mesh = (DM_Plex*) dm->data; 3729 3730 PetscFunctionBegin; 3731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3732 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3733 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3734 PetscFunctionReturn(0); 3735 } 3736 3737 PetscErrorCode DMSetUp_Plex(DM dm) 3738 { 3739 DM_Plex *mesh = (DM_Plex*) dm->data; 3740 PetscInt size, maxSupportSize; 3741 3742 PetscFunctionBegin; 3743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3744 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3745 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3746 PetscCall(PetscMalloc1(size, &mesh->cones)); 3747 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3748 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3749 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3750 if (maxSupportSize) { 3751 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3752 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3753 PetscCall(PetscMalloc1(size, &mesh->supports)); 3754 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3755 } 3756 PetscFunctionReturn(0); 3757 } 3758 3759 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3760 { 3761 PetscFunctionBegin; 3762 if (subdm) PetscCall(DMClone(dm, subdm)); 3763 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3764 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3765 if (dm->useNatural && dm->sfMigration) { 3766 PetscSF sfMigrationInv,sfNatural; 3767 PetscSection section, sectionSeq; 3768 3769 (*subdm)->sfMigration = dm->sfMigration; 3770 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3771 PetscCall(DMGetLocalSection((*subdm), §ion)); 3772 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3773 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3774 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3775 3776 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3777 (*subdm)->sfNatural = sfNatural; 3778 PetscCall(PetscSectionDestroy(§ionSeq)); 3779 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3780 } 3781 PetscFunctionReturn(0); 3782 } 3783 3784 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3785 { 3786 PetscInt i = 0; 3787 3788 PetscFunctionBegin; 3789 PetscCall(DMClone(dms[0], superdm)); 3790 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3791 (*superdm)->useNatural = PETSC_FALSE; 3792 for (i = 0; i < len; i++) { 3793 if (dms[i]->useNatural && dms[i]->sfMigration) { 3794 PetscSF sfMigrationInv,sfNatural; 3795 PetscSection section, sectionSeq; 3796 3797 (*superdm)->sfMigration = dms[i]->sfMigration; 3798 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3799 (*superdm)->useNatural = PETSC_TRUE; 3800 PetscCall(DMGetLocalSection((*superdm), §ion)); 3801 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3802 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3803 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3804 3805 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3806 (*superdm)->sfNatural = sfNatural; 3807 PetscCall(PetscSectionDestroy(§ionSeq)); 3808 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3809 break; 3810 } 3811 } 3812 PetscFunctionReturn(0); 3813 } 3814 3815 /*@ 3816 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3817 3818 Not collective 3819 3820 Input Parameter: 3821 . mesh - The DMPlex 3822 3823 Output Parameter: 3824 3825 Note: 3826 This should be called after all calls to DMPlexSetCone() 3827 3828 Level: beginner 3829 3830 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3831 @*/ 3832 PetscErrorCode DMPlexSymmetrize(DM dm) 3833 { 3834 DM_Plex *mesh = (DM_Plex*) dm->data; 3835 PetscInt *offsets; 3836 PetscInt supportSize; 3837 PetscInt pStart, pEnd, p; 3838 3839 PetscFunctionBegin; 3840 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3841 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3842 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3843 /* Calculate support sizes */ 3844 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3845 for (p = pStart; p < pEnd; ++p) { 3846 PetscInt dof, off, c; 3847 3848 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3849 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3850 for (c = off; c < off+dof; ++c) { 3851 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3852 } 3853 } 3854 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3855 /* Calculate supports */ 3856 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3857 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3858 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3859 for (p = pStart; p < pEnd; ++p) { 3860 PetscInt dof, off, c; 3861 3862 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3863 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3864 for (c = off; c < off+dof; ++c) { 3865 const PetscInt q = mesh->cones[c]; 3866 PetscInt offS; 3867 3868 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3869 3870 mesh->supports[offS+offsets[q]] = p; 3871 ++offsets[q]; 3872 } 3873 } 3874 PetscCall(PetscFree(offsets)); 3875 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3876 PetscFunctionReturn(0); 3877 } 3878 3879 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3880 { 3881 IS stratumIS; 3882 3883 PetscFunctionBegin; 3884 if (pStart >= pEnd) PetscFunctionReturn(0); 3885 if (PetscDefined(USE_DEBUG)) { 3886 PetscInt qStart, qEnd, numLevels, level; 3887 PetscBool overlap = PETSC_FALSE; 3888 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3889 for (level = 0; level < numLevels; level++) { 3890 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3891 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3892 } 3893 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); 3894 } 3895 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3896 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3897 PetscCall(ISDestroy(&stratumIS)); 3898 PetscFunctionReturn(0); 3899 } 3900 3901 /*@ 3902 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3903 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3904 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3905 the DAG. 3906 3907 Collective on dm 3908 3909 Input Parameter: 3910 . mesh - The DMPlex 3911 3912 Output Parameter: 3913 3914 Notes: 3915 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3916 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3917 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3918 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3919 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3920 3921 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3922 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3923 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 3924 to interpolate only that one (e0), so that 3925 $ cone(c0) = {e0, v2} 3926 $ cone(e0) = {v0, v1} 3927 If DMPlexStratify() is run on this mesh, it will give depths 3928 $ depth 0 = {v0, v1, v2} 3929 $ depth 1 = {e0, c0} 3930 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3931 3932 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3933 3934 Level: beginner 3935 3936 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3937 @*/ 3938 PetscErrorCode DMPlexStratify(DM dm) 3939 { 3940 DM_Plex *mesh = (DM_Plex*) dm->data; 3941 DMLabel label; 3942 PetscInt pStart, pEnd, p; 3943 PetscInt numRoots = 0, numLeaves = 0; 3944 3945 PetscFunctionBegin; 3946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3947 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3948 3949 /* Create depth label */ 3950 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3951 PetscCall(DMCreateLabel(dm, "depth")); 3952 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3953 3954 { 3955 /* Initialize roots and count leaves */ 3956 PetscInt sMin = PETSC_MAX_INT; 3957 PetscInt sMax = PETSC_MIN_INT; 3958 PetscInt coneSize, supportSize; 3959 3960 for (p = pStart; p < pEnd; ++p) { 3961 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3962 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3963 if (!coneSize && supportSize) { 3964 sMin = PetscMin(p, sMin); 3965 sMax = PetscMax(p, sMax); 3966 ++numRoots; 3967 } else if (!supportSize && coneSize) { 3968 ++numLeaves; 3969 } else if (!supportSize && !coneSize) { 3970 /* Isolated points */ 3971 sMin = PetscMin(p, sMin); 3972 sMax = PetscMax(p, sMax); 3973 } 3974 } 3975 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3976 } 3977 3978 if (numRoots + numLeaves == (pEnd - pStart)) { 3979 PetscInt sMin = PETSC_MAX_INT; 3980 PetscInt sMax = PETSC_MIN_INT; 3981 PetscInt coneSize, supportSize; 3982 3983 for (p = pStart; p < pEnd; ++p) { 3984 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3985 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3986 if (!supportSize && coneSize) { 3987 sMin = PetscMin(p, sMin); 3988 sMax = PetscMax(p, sMax); 3989 } 3990 } 3991 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3992 } else { 3993 PetscInt level = 0; 3994 PetscInt qStart, qEnd, q; 3995 3996 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3997 while (qEnd > qStart) { 3998 PetscInt sMin = PETSC_MAX_INT; 3999 PetscInt sMax = PETSC_MIN_INT; 4000 4001 for (q = qStart; q < qEnd; ++q) { 4002 const PetscInt *support; 4003 PetscInt supportSize, s; 4004 4005 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4006 PetscCall(DMPlexGetSupport(dm, q, &support)); 4007 for (s = 0; s < supportSize; ++s) { 4008 sMin = PetscMin(support[s], sMin); 4009 sMax = PetscMax(support[s], sMax); 4010 } 4011 } 4012 PetscCall(DMLabelGetNumValues(label, &level)); 4013 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4014 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4015 } 4016 } 4017 { /* just in case there is an empty process */ 4018 PetscInt numValues, maxValues = 0, v; 4019 4020 PetscCall(DMLabelGetNumValues(label, &numValues)); 4021 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4022 for (v = numValues; v < maxValues; v++) { 4023 PetscCall(DMLabelAddStratum(label, v)); 4024 } 4025 } 4026 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4027 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4028 PetscFunctionReturn(0); 4029 } 4030 4031 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4032 { 4033 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4034 PetscInt dim, depth, pheight, coneSize; 4035 4036 PetscFunctionBeginHot; 4037 PetscCall(DMGetDimension(dm, &dim)); 4038 PetscCall(DMPlexGetDepth(dm, &depth)); 4039 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4040 pheight = depth - pdepth; 4041 if (depth <= 1) { 4042 switch (pdepth) { 4043 case 0: ct = DM_POLYTOPE_POINT;break; 4044 case 1: 4045 switch (coneSize) { 4046 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4047 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4048 case 4: 4049 switch (dim) { 4050 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4051 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4052 default: break; 4053 } 4054 break; 4055 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4056 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4057 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4058 default: break; 4059 } 4060 } 4061 } else { 4062 if (pdepth == 0) { 4063 ct = DM_POLYTOPE_POINT; 4064 } else if (pheight == 0) { 4065 switch (dim) { 4066 case 1: 4067 switch (coneSize) { 4068 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4069 default: break; 4070 } 4071 break; 4072 case 2: 4073 switch (coneSize) { 4074 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4075 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4076 default: break; 4077 } 4078 break; 4079 case 3: 4080 switch (coneSize) { 4081 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4082 case 5: 4083 { 4084 const PetscInt *cone; 4085 PetscInt faceConeSize; 4086 4087 PetscCall(DMPlexGetCone(dm, p, &cone)); 4088 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4089 switch (faceConeSize) { 4090 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4091 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4092 } 4093 } 4094 break; 4095 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4096 default: break; 4097 } 4098 break; 4099 default: break; 4100 } 4101 } else if (pheight > 0) { 4102 switch (coneSize) { 4103 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4104 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4105 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4106 default: break; 4107 } 4108 } 4109 } 4110 *pt = ct; 4111 PetscFunctionReturn(0); 4112 } 4113 4114 /*@ 4115 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4116 4117 Collective on dm 4118 4119 Input Parameter: 4120 . mesh - The DMPlex 4121 4122 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4123 4124 Level: developer 4125 4126 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4127 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4128 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4129 4130 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4131 @*/ 4132 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4133 { 4134 DM_Plex *mesh; 4135 DMLabel ctLabel; 4136 PetscInt pStart, pEnd, p; 4137 4138 PetscFunctionBegin; 4139 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4140 mesh = (DM_Plex *) dm->data; 4141 PetscCall(DMCreateLabel(dm, "celltype")); 4142 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4143 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4144 for (p = pStart; p < pEnd; ++p) { 4145 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4146 PetscInt pdepth; 4147 4148 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4149 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4150 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4151 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4152 } 4153 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4154 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4155 PetscFunctionReturn(0); 4156 } 4157 4158 /*@C 4159 DMPlexGetJoin - Get an array for the join of the set of points 4160 4161 Not Collective 4162 4163 Input Parameters: 4164 + dm - The DMPlex object 4165 . numPoints - The number of input points for the join 4166 - points - The input points 4167 4168 Output Parameters: 4169 + numCoveredPoints - The number of points in the join 4170 - coveredPoints - The points in the join 4171 4172 Level: intermediate 4173 4174 Note: Currently, this is restricted to a single level join 4175 4176 Fortran Notes: 4177 Since it returns an array, this routine is only available in Fortran 90, and you must 4178 include petsc.h90 in your code. 4179 4180 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4181 4182 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4183 @*/ 4184 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4185 { 4186 DM_Plex *mesh = (DM_Plex*) dm->data; 4187 PetscInt *join[2]; 4188 PetscInt joinSize, i = 0; 4189 PetscInt dof, off, p, c, m; 4190 PetscInt maxSupportSize; 4191 4192 PetscFunctionBegin; 4193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4194 PetscValidIntPointer(points, 3); 4195 PetscValidIntPointer(numCoveredPoints, 4); 4196 PetscValidPointer(coveredPoints, 5); 4197 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4198 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4199 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4200 /* Copy in support of first point */ 4201 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4202 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4203 for (joinSize = 0; joinSize < dof; ++joinSize) { 4204 join[i][joinSize] = mesh->supports[off+joinSize]; 4205 } 4206 /* Check each successive support */ 4207 for (p = 1; p < numPoints; ++p) { 4208 PetscInt newJoinSize = 0; 4209 4210 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4211 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4212 for (c = 0; c < dof; ++c) { 4213 const PetscInt point = mesh->supports[off+c]; 4214 4215 for (m = 0; m < joinSize; ++m) { 4216 if (point == join[i][m]) { 4217 join[1-i][newJoinSize++] = point; 4218 break; 4219 } 4220 } 4221 } 4222 joinSize = newJoinSize; 4223 i = 1-i; 4224 } 4225 *numCoveredPoints = joinSize; 4226 *coveredPoints = join[i]; 4227 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4228 PetscFunctionReturn(0); 4229 } 4230 4231 /*@C 4232 DMPlexRestoreJoin - Restore an array for the join of the set of points 4233 4234 Not Collective 4235 4236 Input Parameters: 4237 + dm - The DMPlex object 4238 . numPoints - The number of input points for the join 4239 - points - The input points 4240 4241 Output Parameters: 4242 + numCoveredPoints - The number of points in the join 4243 - coveredPoints - The points in the join 4244 4245 Fortran Notes: 4246 Since it returns an array, this routine is only available in Fortran 90, and you must 4247 include petsc.h90 in your code. 4248 4249 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4250 4251 Level: intermediate 4252 4253 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4254 @*/ 4255 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4256 { 4257 PetscFunctionBegin; 4258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4259 if (points) PetscValidIntPointer(points,3); 4260 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4261 PetscValidPointer(coveredPoints, 5); 4262 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4263 if (numCoveredPoints) *numCoveredPoints = 0; 4264 PetscFunctionReturn(0); 4265 } 4266 4267 /*@C 4268 DMPlexGetFullJoin - Get an array for the join of the set of points 4269 4270 Not Collective 4271 4272 Input Parameters: 4273 + dm - The DMPlex object 4274 . numPoints - The number of input points for the join 4275 - points - The input points 4276 4277 Output Parameters: 4278 + numCoveredPoints - The number of points in the join 4279 - coveredPoints - The points in the join 4280 4281 Fortran Notes: 4282 Since it returns an array, this routine is only available in Fortran 90, and you must 4283 include petsc.h90 in your code. 4284 4285 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4286 4287 Level: intermediate 4288 4289 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4290 @*/ 4291 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4292 { 4293 PetscInt *offsets, **closures; 4294 PetscInt *join[2]; 4295 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4296 PetscInt p, d, c, m, ms; 4297 4298 PetscFunctionBegin; 4299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4300 PetscValidIntPointer(points, 3); 4301 PetscValidIntPointer(numCoveredPoints, 4); 4302 PetscValidPointer(coveredPoints, 5); 4303 4304 PetscCall(DMPlexGetDepth(dm, &depth)); 4305 PetscCall(PetscCalloc1(numPoints, &closures)); 4306 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4307 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4308 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4309 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4310 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4311 4312 for (p = 0; p < numPoints; ++p) { 4313 PetscInt closureSize; 4314 4315 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4316 4317 offsets[p*(depth+2)+0] = 0; 4318 for (d = 0; d < depth+1; ++d) { 4319 PetscInt pStart, pEnd, i; 4320 4321 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4322 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4323 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4324 offsets[p*(depth+2)+d+1] = i; 4325 break; 4326 } 4327 } 4328 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4329 } 4330 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); 4331 } 4332 for (d = 0; d < depth+1; ++d) { 4333 PetscInt dof; 4334 4335 /* Copy in support of first point */ 4336 dof = offsets[d+1] - offsets[d]; 4337 for (joinSize = 0; joinSize < dof; ++joinSize) { 4338 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4339 } 4340 /* Check each successive cone */ 4341 for (p = 1; p < numPoints && joinSize; ++p) { 4342 PetscInt newJoinSize = 0; 4343 4344 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4345 for (c = 0; c < dof; ++c) { 4346 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4347 4348 for (m = 0; m < joinSize; ++m) { 4349 if (point == join[i][m]) { 4350 join[1-i][newJoinSize++] = point; 4351 break; 4352 } 4353 } 4354 } 4355 joinSize = newJoinSize; 4356 i = 1-i; 4357 } 4358 if (joinSize) break; 4359 } 4360 *numCoveredPoints = joinSize; 4361 *coveredPoints = join[i]; 4362 for (p = 0; p < numPoints; ++p) { 4363 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4364 } 4365 PetscCall(PetscFree(closures)); 4366 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4367 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4368 PetscFunctionReturn(0); 4369 } 4370 4371 /*@C 4372 DMPlexGetMeet - Get an array for the meet of the set of points 4373 4374 Not Collective 4375 4376 Input Parameters: 4377 + dm - The DMPlex object 4378 . numPoints - The number of input points for the meet 4379 - points - The input points 4380 4381 Output Parameters: 4382 + numCoveredPoints - The number of points in the meet 4383 - coveredPoints - The points in the meet 4384 4385 Level: intermediate 4386 4387 Note: Currently, this is restricted to a single level meet 4388 4389 Fortran Notes: 4390 Since it returns an array, this routine is only available in Fortran 90, and you must 4391 include petsc.h90 in your code. 4392 4393 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4394 4395 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4396 @*/ 4397 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4398 { 4399 DM_Plex *mesh = (DM_Plex*) dm->data; 4400 PetscInt *meet[2]; 4401 PetscInt meetSize, i = 0; 4402 PetscInt dof, off, p, c, m; 4403 PetscInt maxConeSize; 4404 4405 PetscFunctionBegin; 4406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4407 PetscValidIntPointer(points, 3); 4408 PetscValidIntPointer(numCoveringPoints, 4); 4409 PetscValidPointer(coveringPoints, 5); 4410 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4411 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4412 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4413 /* Copy in cone of first point */ 4414 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4415 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4416 for (meetSize = 0; meetSize < dof; ++meetSize) { 4417 meet[i][meetSize] = mesh->cones[off+meetSize]; 4418 } 4419 /* Check each successive cone */ 4420 for (p = 1; p < numPoints; ++p) { 4421 PetscInt newMeetSize = 0; 4422 4423 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4424 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4425 for (c = 0; c < dof; ++c) { 4426 const PetscInt point = mesh->cones[off+c]; 4427 4428 for (m = 0; m < meetSize; ++m) { 4429 if (point == meet[i][m]) { 4430 meet[1-i][newMeetSize++] = point; 4431 break; 4432 } 4433 } 4434 } 4435 meetSize = newMeetSize; 4436 i = 1-i; 4437 } 4438 *numCoveringPoints = meetSize; 4439 *coveringPoints = meet[i]; 4440 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4441 PetscFunctionReturn(0); 4442 } 4443 4444 /*@C 4445 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4446 4447 Not Collective 4448 4449 Input Parameters: 4450 + dm - The DMPlex object 4451 . numPoints - The number of input points for the meet 4452 - points - The input points 4453 4454 Output Parameters: 4455 + numCoveredPoints - The number of points in the meet 4456 - coveredPoints - The points in the meet 4457 4458 Level: intermediate 4459 4460 Fortran Notes: 4461 Since it returns an array, this routine is only available in Fortran 90, and you must 4462 include petsc.h90 in your code. 4463 4464 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4465 4466 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4467 @*/ 4468 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4469 { 4470 PetscFunctionBegin; 4471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4472 if (points) PetscValidIntPointer(points,3); 4473 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4474 PetscValidPointer(coveredPoints,5); 4475 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4476 if (numCoveredPoints) *numCoveredPoints = 0; 4477 PetscFunctionReturn(0); 4478 } 4479 4480 /*@C 4481 DMPlexGetFullMeet - Get an array for the meet of the set of points 4482 4483 Not Collective 4484 4485 Input Parameters: 4486 + dm - The DMPlex object 4487 . numPoints - The number of input points for the meet 4488 - points - The input points 4489 4490 Output Parameters: 4491 + numCoveredPoints - The number of points in the meet 4492 - coveredPoints - The points in the meet 4493 4494 Level: intermediate 4495 4496 Fortran Notes: 4497 Since it returns an array, this routine is only available in Fortran 90, and you must 4498 include petsc.h90 in your code. 4499 4500 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4501 4502 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4503 @*/ 4504 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4505 { 4506 PetscInt *offsets, **closures; 4507 PetscInt *meet[2]; 4508 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4509 PetscInt p, h, c, m, mc; 4510 4511 PetscFunctionBegin; 4512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4513 PetscValidIntPointer(points, 3); 4514 PetscValidIntPointer(numCoveredPoints, 4); 4515 PetscValidPointer(coveredPoints, 5); 4516 4517 PetscCall(DMPlexGetDepth(dm, &height)); 4518 PetscCall(PetscMalloc1(numPoints, &closures)); 4519 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4520 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4521 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4522 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4523 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4524 4525 for (p = 0; p < numPoints; ++p) { 4526 PetscInt closureSize; 4527 4528 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4529 4530 offsets[p*(height+2)+0] = 0; 4531 for (h = 0; h < height+1; ++h) { 4532 PetscInt pStart, pEnd, i; 4533 4534 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4535 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4536 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4537 offsets[p*(height+2)+h+1] = i; 4538 break; 4539 } 4540 } 4541 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4542 } 4543 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); 4544 } 4545 for (h = 0; h < height+1; ++h) { 4546 PetscInt dof; 4547 4548 /* Copy in cone of first point */ 4549 dof = offsets[h+1] - offsets[h]; 4550 for (meetSize = 0; meetSize < dof; ++meetSize) { 4551 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4552 } 4553 /* Check each successive cone */ 4554 for (p = 1; p < numPoints && meetSize; ++p) { 4555 PetscInt newMeetSize = 0; 4556 4557 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4558 for (c = 0; c < dof; ++c) { 4559 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4560 4561 for (m = 0; m < meetSize; ++m) { 4562 if (point == meet[i][m]) { 4563 meet[1-i][newMeetSize++] = point; 4564 break; 4565 } 4566 } 4567 } 4568 meetSize = newMeetSize; 4569 i = 1-i; 4570 } 4571 if (meetSize) break; 4572 } 4573 *numCoveredPoints = meetSize; 4574 *coveredPoints = meet[i]; 4575 for (p = 0; p < numPoints; ++p) { 4576 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4577 } 4578 PetscCall(PetscFree(closures)); 4579 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4580 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4581 PetscFunctionReturn(0); 4582 } 4583 4584 /*@C 4585 DMPlexEqual - Determine if two DMs have the same topology 4586 4587 Not Collective 4588 4589 Input Parameters: 4590 + dmA - A DMPlex object 4591 - dmB - A DMPlex object 4592 4593 Output Parameters: 4594 . equal - PETSC_TRUE if the topologies are identical 4595 4596 Level: intermediate 4597 4598 Notes: 4599 We are not solving graph isomorphism, so we do not permutation. 4600 4601 .seealso: `DMPlexGetCone()` 4602 @*/ 4603 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4604 { 4605 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4606 4607 PetscFunctionBegin; 4608 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4609 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4610 PetscValidBoolPointer(equal, 3); 4611 4612 *equal = PETSC_FALSE; 4613 PetscCall(DMPlexGetDepth(dmA, &depth)); 4614 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4615 if (depth != depthB) PetscFunctionReturn(0); 4616 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4617 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4618 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4619 for (p = pStart; p < pEnd; ++p) { 4620 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4621 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4622 4623 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4624 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4625 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4626 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4627 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4628 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4629 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4630 for (c = 0; c < coneSize; ++c) { 4631 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4632 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4633 } 4634 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4635 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4636 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4637 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4638 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4639 for (s = 0; s < supportSize; ++s) { 4640 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4641 } 4642 } 4643 *equal = PETSC_TRUE; 4644 PetscFunctionReturn(0); 4645 } 4646 4647 /*@C 4648 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4649 4650 Not Collective 4651 4652 Input Parameters: 4653 + dm - The DMPlex 4654 . cellDim - The cell dimension 4655 - numCorners - The number of vertices on a cell 4656 4657 Output Parameters: 4658 . numFaceVertices - The number of vertices on a face 4659 4660 Level: developer 4661 4662 Notes: 4663 Of course this can only work for a restricted set of symmetric shapes 4664 4665 .seealso: `DMPlexGetCone()` 4666 @*/ 4667 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4668 { 4669 MPI_Comm comm; 4670 4671 PetscFunctionBegin; 4672 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4673 PetscValidIntPointer(numFaceVertices,4); 4674 switch (cellDim) { 4675 case 0: 4676 *numFaceVertices = 0; 4677 break; 4678 case 1: 4679 *numFaceVertices = 1; 4680 break; 4681 case 2: 4682 switch (numCorners) { 4683 case 3: /* triangle */ 4684 *numFaceVertices = 2; /* Edge has 2 vertices */ 4685 break; 4686 case 4: /* quadrilateral */ 4687 *numFaceVertices = 2; /* Edge has 2 vertices */ 4688 break; 4689 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4690 *numFaceVertices = 3; /* Edge has 3 vertices */ 4691 break; 4692 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4693 *numFaceVertices = 3; /* Edge has 3 vertices */ 4694 break; 4695 default: 4696 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4697 } 4698 break; 4699 case 3: 4700 switch (numCorners) { 4701 case 4: /* tetradehdron */ 4702 *numFaceVertices = 3; /* Face has 3 vertices */ 4703 break; 4704 case 6: /* tet cohesive cells */ 4705 *numFaceVertices = 4; /* Face has 4 vertices */ 4706 break; 4707 case 8: /* hexahedron */ 4708 *numFaceVertices = 4; /* Face has 4 vertices */ 4709 break; 4710 case 9: /* tet cohesive Lagrange cells */ 4711 *numFaceVertices = 6; /* Face has 6 vertices */ 4712 break; 4713 case 10: /* quadratic tetrahedron */ 4714 *numFaceVertices = 6; /* Face has 6 vertices */ 4715 break; 4716 case 12: /* hex cohesive Lagrange cells */ 4717 *numFaceVertices = 6; /* Face has 6 vertices */ 4718 break; 4719 case 18: /* quadratic tet cohesive Lagrange cells */ 4720 *numFaceVertices = 6; /* Face has 6 vertices */ 4721 break; 4722 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4723 *numFaceVertices = 9; /* Face has 9 vertices */ 4724 break; 4725 default: 4726 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4727 } 4728 break; 4729 default: 4730 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4731 } 4732 PetscFunctionReturn(0); 4733 } 4734 4735 /*@ 4736 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4737 4738 Not Collective 4739 4740 Input Parameter: 4741 . dm - The DMPlex object 4742 4743 Output Parameter: 4744 . depthLabel - The DMLabel recording point depth 4745 4746 Level: developer 4747 4748 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4749 @*/ 4750 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4751 { 4752 PetscFunctionBegin; 4753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4754 PetscValidPointer(depthLabel, 2); 4755 *depthLabel = dm->depthLabel; 4756 PetscFunctionReturn(0); 4757 } 4758 4759 /*@ 4760 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4761 4762 Not Collective 4763 4764 Input Parameter: 4765 . dm - The DMPlex object 4766 4767 Output Parameter: 4768 . depth - The number of strata (breadth first levels) in the DAG 4769 4770 Level: developer 4771 4772 Notes: 4773 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4774 The point depth is described more in detail in DMPlexGetDepthStratum(). 4775 An empty mesh gives -1. 4776 4777 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4778 @*/ 4779 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4780 { 4781 DMLabel label; 4782 PetscInt d = 0; 4783 4784 PetscFunctionBegin; 4785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4786 PetscValidIntPointer(depth, 2); 4787 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4788 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4789 *depth = d-1; 4790 PetscFunctionReturn(0); 4791 } 4792 4793 /*@ 4794 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4795 4796 Not Collective 4797 4798 Input Parameters: 4799 + dm - The DMPlex object 4800 - depth - The requested depth 4801 4802 Output Parameters: 4803 + start - The first point at this depth 4804 - end - One beyond the last point at this depth 4805 4806 Notes: 4807 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4808 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4809 higher dimension, e.g., "edges". 4810 4811 Level: developer 4812 4813 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4814 @*/ 4815 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4816 { 4817 DMLabel label; 4818 PetscInt pStart, pEnd; 4819 4820 PetscFunctionBegin; 4821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4822 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4823 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4824 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4825 if (pStart == pEnd) PetscFunctionReturn(0); 4826 if (depth < 0) { 4827 if (start) *start = pStart; 4828 if (end) *end = pEnd; 4829 PetscFunctionReturn(0); 4830 } 4831 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4832 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4833 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4834 PetscFunctionReturn(0); 4835 } 4836 4837 /*@ 4838 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4839 4840 Not Collective 4841 4842 Input Parameters: 4843 + dm - The DMPlex object 4844 - height - The requested height 4845 4846 Output Parameters: 4847 + start - The first point at this height 4848 - end - One beyond the last point at this height 4849 4850 Notes: 4851 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4852 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4853 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4854 4855 Level: developer 4856 4857 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4858 @*/ 4859 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4860 { 4861 DMLabel label; 4862 PetscInt depth, pStart, pEnd; 4863 4864 PetscFunctionBegin; 4865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4866 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4867 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4868 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4869 if (pStart == pEnd) PetscFunctionReturn(0); 4870 if (height < 0) { 4871 if (start) *start = pStart; 4872 if (end) *end = pEnd; 4873 PetscFunctionReturn(0); 4874 } 4875 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4876 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4877 PetscCall(DMLabelGetNumValues(label, &depth)); 4878 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4879 PetscFunctionReturn(0); 4880 } 4881 4882 /*@ 4883 DMPlexGetPointDepth - Get the depth of a given point 4884 4885 Not Collective 4886 4887 Input Parameters: 4888 + dm - The DMPlex object 4889 - point - The point 4890 4891 Output Parameter: 4892 . depth - The depth of the point 4893 4894 Level: intermediate 4895 4896 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4897 @*/ 4898 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4899 { 4900 PetscFunctionBegin; 4901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4902 PetscValidIntPointer(depth, 3); 4903 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetPointHeight - Get the height of a given point 4909 4910 Not Collective 4911 4912 Input Parameters: 4913 + dm - The DMPlex object 4914 - point - The point 4915 4916 Output Parameter: 4917 . height - The height of the point 4918 4919 Level: intermediate 4920 4921 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4922 @*/ 4923 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4924 { 4925 PetscInt n, pDepth; 4926 4927 PetscFunctionBegin; 4928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4929 PetscValidIntPointer(height, 3); 4930 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4931 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4932 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4933 PetscFunctionReturn(0); 4934 } 4935 4936 /*@ 4937 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4938 4939 Not Collective 4940 4941 Input Parameter: 4942 . dm - The DMPlex object 4943 4944 Output Parameter: 4945 . celltypeLabel - The DMLabel recording cell polytope type 4946 4947 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4948 DMCreateLabel(dm, "celltype") beforehand. 4949 4950 Level: developer 4951 4952 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4953 @*/ 4954 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4955 { 4956 PetscFunctionBegin; 4957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4958 PetscValidPointer(celltypeLabel, 2); 4959 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4960 *celltypeLabel = dm->celltypeLabel; 4961 PetscFunctionReturn(0); 4962 } 4963 4964 /*@ 4965 DMPlexGetCellType - Get the polytope type of a given cell 4966 4967 Not Collective 4968 4969 Input Parameters: 4970 + dm - The DMPlex object 4971 - cell - The cell 4972 4973 Output Parameter: 4974 . celltype - The polytope type of the cell 4975 4976 Level: intermediate 4977 4978 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4979 @*/ 4980 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4981 { 4982 DMLabel label; 4983 PetscInt ct; 4984 4985 PetscFunctionBegin; 4986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4987 PetscValidPointer(celltype, 3); 4988 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4989 PetscCall(DMLabelGetValue(label, cell, &ct)); 4990 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4991 *celltype = (DMPolytopeType) ct; 4992 PetscFunctionReturn(0); 4993 } 4994 4995 /*@ 4996 DMPlexSetCellType - Set the polytope type of a given cell 4997 4998 Not Collective 4999 5000 Input Parameters: 5001 + dm - The DMPlex object 5002 . cell - The cell 5003 - celltype - The polytope type of the cell 5004 5005 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5006 is executed. This function will override the computed type. However, if automatic classification will not succeed 5007 and a user wants to manually specify all types, the classification must be disabled by calling 5008 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5009 5010 Level: advanced 5011 5012 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5013 @*/ 5014 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5015 { 5016 DMLabel label; 5017 5018 PetscFunctionBegin; 5019 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5020 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5021 PetscCall(DMLabelSetValue(label, cell, celltype)); 5022 PetscFunctionReturn(0); 5023 } 5024 5025 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5026 { 5027 PetscSection section, s; 5028 Mat m; 5029 PetscInt maxHeight; 5030 5031 PetscFunctionBegin; 5032 PetscCall(DMClone(dm, cdm)); 5033 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5034 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5035 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5036 PetscCall(DMSetLocalSection(*cdm, section)); 5037 PetscCall(PetscSectionDestroy(§ion)); 5038 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5039 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5040 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5041 PetscCall(PetscSectionDestroy(&s)); 5042 PetscCall(MatDestroy(&m)); 5043 5044 PetscCall(DMSetNumFields(*cdm, 1)); 5045 PetscCall(DMCreateDS(*cdm)); 5046 PetscFunctionReturn(0); 5047 } 5048 5049 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5050 { 5051 Vec coordsLocal, cellCoordsLocal; 5052 DM coordsDM, cellCoordsDM; 5053 5054 PetscFunctionBegin; 5055 *field = NULL; 5056 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5057 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5058 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5059 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5060 if (coordsLocal && coordsDM) { 5061 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5062 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5063 } 5064 PetscFunctionReturn(0); 5065 } 5066 5067 /*@C 5068 DMPlexGetConeSection - Return a section which describes the layout of cone data 5069 5070 Not Collective 5071 5072 Input Parameters: 5073 . dm - The DMPlex object 5074 5075 Output Parameter: 5076 . section - The PetscSection object 5077 5078 Level: developer 5079 5080 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5081 @*/ 5082 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5083 { 5084 DM_Plex *mesh = (DM_Plex*) dm->data; 5085 5086 PetscFunctionBegin; 5087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5088 if (section) *section = mesh->coneSection; 5089 PetscFunctionReturn(0); 5090 } 5091 5092 /*@C 5093 DMPlexGetSupportSection - Return a section which describes the layout of support data 5094 5095 Not Collective 5096 5097 Input Parameters: 5098 . dm - The DMPlex object 5099 5100 Output Parameter: 5101 . section - The PetscSection object 5102 5103 Level: developer 5104 5105 .seealso: `DMPlexGetConeSection()` 5106 @*/ 5107 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5108 { 5109 DM_Plex *mesh = (DM_Plex*) dm->data; 5110 5111 PetscFunctionBegin; 5112 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5113 if (section) *section = mesh->supportSection; 5114 PetscFunctionReturn(0); 5115 } 5116 5117 /*@C 5118 DMPlexGetCones - Return cone data 5119 5120 Not Collective 5121 5122 Input Parameters: 5123 . dm - The DMPlex object 5124 5125 Output Parameter: 5126 . cones - The cone for each point 5127 5128 Level: developer 5129 5130 .seealso: `DMPlexGetConeSection()` 5131 @*/ 5132 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5133 { 5134 DM_Plex *mesh = (DM_Plex*) dm->data; 5135 5136 PetscFunctionBegin; 5137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5138 if (cones) *cones = mesh->cones; 5139 PetscFunctionReturn(0); 5140 } 5141 5142 /*@C 5143 DMPlexGetConeOrientations - Return cone orientation data 5144 5145 Not Collective 5146 5147 Input Parameters: 5148 . dm - The DMPlex object 5149 5150 Output Parameter: 5151 . coneOrientations - The array of cone orientations for all points 5152 5153 Level: developer 5154 5155 Notes: 5156 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5157 5158 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5159 5160 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5161 @*/ 5162 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5163 { 5164 DM_Plex *mesh = (DM_Plex*) dm->data; 5165 5166 PetscFunctionBegin; 5167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5168 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5169 PetscFunctionReturn(0); 5170 } 5171 5172 /******************************** FEM Support **********************************/ 5173 5174 /* 5175 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5176 representing a line in the section. 5177 */ 5178 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5179 { 5180 PetscFunctionBeginHot; 5181 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5182 if (line < 0) { 5183 *k = 0; 5184 *Nc = 0; 5185 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5186 *k = 1; 5187 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5188 /* An order k SEM disc has k-1 dofs on an edge */ 5189 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5190 *k = *k / *Nc + 1; 5191 } 5192 PetscFunctionReturn(0); 5193 } 5194 5195 /*@ 5196 5197 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5198 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5199 section provided (or the section of the DM). 5200 5201 Input Parameters: 5202 + dm - The DM 5203 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5204 - section - The PetscSection to reorder, or NULL for the default section 5205 5206 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5207 degree of the basis. 5208 5209 Example: 5210 A typical interpolated single-quad mesh might order points as 5211 .vb 5212 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5213 5214 v4 -- e6 -- v3 5215 | | 5216 e7 c0 e8 5217 | | 5218 v1 -- e5 -- v2 5219 .ve 5220 5221 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5222 dofs in the order of points, e.g., 5223 .vb 5224 c0 -> [0,1,2,3] 5225 v1 -> [4] 5226 ... 5227 e5 -> [8, 9] 5228 .ve 5229 5230 which corresponds to the dofs 5231 .vb 5232 6 10 11 7 5233 13 2 3 15 5234 12 0 1 14 5235 4 8 9 5 5236 .ve 5237 5238 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5239 .vb 5240 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5241 .ve 5242 5243 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5244 .vb 5245 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5246 .ve 5247 5248 Level: developer 5249 5250 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5251 @*/ 5252 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5253 { 5254 DMLabel label; 5255 PetscInt dim, depth = -1, eStart = -1, Nf; 5256 PetscBool vertexchart; 5257 5258 PetscFunctionBegin; 5259 PetscCall(DMGetDimension(dm, &dim)); 5260 if (dim < 1) PetscFunctionReturn(0); 5261 if (point < 0) { 5262 PetscInt sStart,sEnd; 5263 5264 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5265 point = sEnd-sStart ? sStart : point; 5266 } 5267 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5268 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5269 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5270 if (depth == 1) {eStart = point;} 5271 else if (depth == dim) { 5272 const PetscInt *cone; 5273 5274 PetscCall(DMPlexGetCone(dm, point, &cone)); 5275 if (dim == 2) eStart = cone[0]; 5276 else if (dim == 3) { 5277 const PetscInt *cone2; 5278 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5279 eStart = cone2[0]; 5280 } 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); 5281 } 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); 5282 { /* Determine whether the chart covers all points or just vertices. */ 5283 PetscInt pStart,pEnd,cStart,cEnd; 5284 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5285 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5286 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5287 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5288 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5289 } 5290 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5291 for (PetscInt d=1; d<=dim; d++) { 5292 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5293 PetscInt *perm; 5294 5295 for (f = 0; f < Nf; ++f) { 5296 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5297 size += PetscPowInt(k+1, d)*Nc; 5298 } 5299 PetscCall(PetscMalloc1(size, &perm)); 5300 for (f = 0; f < Nf; ++f) { 5301 switch (d) { 5302 case 1: 5303 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5304 /* 5305 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5306 We want [ vtx0; edge of length k-1; vtx1 ] 5307 */ 5308 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5309 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5310 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5311 foffset = offset; 5312 break; 5313 case 2: 5314 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5315 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5316 /* The SEM order is 5317 5318 v_lb, {e_b}, v_rb, 5319 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5320 v_lt, reverse {e_t}, v_rt 5321 */ 5322 { 5323 const PetscInt of = 0; 5324 const PetscInt oeb = of + PetscSqr(k-1); 5325 const PetscInt oer = oeb + (k-1); 5326 const PetscInt oet = oer + (k-1); 5327 const PetscInt oel = oet + (k-1); 5328 const PetscInt ovlb = oel + (k-1); 5329 const PetscInt ovrb = ovlb + 1; 5330 const PetscInt ovrt = ovrb + 1; 5331 const PetscInt ovlt = ovrt + 1; 5332 PetscInt o; 5333 5334 /* bottom */ 5335 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5336 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5337 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5338 /* middle */ 5339 for (i = 0; i < k-1; ++i) { 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5341 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; 5342 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5343 } 5344 /* top */ 5345 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5346 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5348 foffset = offset; 5349 } 5350 break; 5351 case 3: 5352 /* The original hex closure is 5353 5354 {c, 5355 f_b, f_t, f_f, f_b, f_r, f_l, 5356 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5357 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5358 */ 5359 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5360 /* The SEM order is 5361 Bottom Slice 5362 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5363 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5364 v_blb, {e_bb}, v_brb, 5365 5366 Middle Slice (j) 5367 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5368 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5369 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5370 5371 Top Slice 5372 v_tlf, {e_tf}, v_trf, 5373 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5374 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5375 */ 5376 { 5377 const PetscInt oc = 0; 5378 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5379 const PetscInt oft = ofb + PetscSqr(k-1); 5380 const PetscInt off = oft + PetscSqr(k-1); 5381 const PetscInt ofk = off + PetscSqr(k-1); 5382 const PetscInt ofr = ofk + PetscSqr(k-1); 5383 const PetscInt ofl = ofr + PetscSqr(k-1); 5384 const PetscInt oebl = ofl + PetscSqr(k-1); 5385 const PetscInt oebb = oebl + (k-1); 5386 const PetscInt oebr = oebb + (k-1); 5387 const PetscInt oebf = oebr + (k-1); 5388 const PetscInt oetf = oebf + (k-1); 5389 const PetscInt oetr = oetf + (k-1); 5390 const PetscInt oetb = oetr + (k-1); 5391 const PetscInt oetl = oetb + (k-1); 5392 const PetscInt oerf = oetl + (k-1); 5393 const PetscInt oelf = oerf + (k-1); 5394 const PetscInt oelb = oelf + (k-1); 5395 const PetscInt oerb = oelb + (k-1); 5396 const PetscInt ovblf = oerb + (k-1); 5397 const PetscInt ovblb = ovblf + 1; 5398 const PetscInt ovbrb = ovblb + 1; 5399 const PetscInt ovbrf = ovbrb + 1; 5400 const PetscInt ovtlf = ovbrf + 1; 5401 const PetscInt ovtrf = ovtlf + 1; 5402 const PetscInt ovtrb = ovtrf + 1; 5403 const PetscInt ovtlb = ovtrb + 1; 5404 PetscInt o, n; 5405 5406 /* Bottom Slice */ 5407 /* bottom */ 5408 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5409 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5410 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5411 /* middle */ 5412 for (i = 0; i < k-1; ++i) { 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5414 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;} 5415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5416 } 5417 /* top */ 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5419 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5421 5422 /* Middle Slice */ 5423 for (j = 0; j < k-1; ++j) { 5424 /* bottom */ 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5426 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; 5427 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5428 /* middle */ 5429 for (i = 0; i < k-1; ++i) { 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5431 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; 5432 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5433 } 5434 /* top */ 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5436 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; 5437 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5438 } 5439 5440 /* Top Slice */ 5441 /* bottom */ 5442 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5443 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5444 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5445 /* middle */ 5446 for (i = 0; i < k-1; ++i) { 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5448 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5449 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5450 } 5451 /* top */ 5452 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5453 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5454 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5455 5456 foffset = offset; 5457 } 5458 break; 5459 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5460 } 5461 } 5462 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5463 /* Check permutation */ 5464 { 5465 PetscInt *check; 5466 5467 PetscCall(PetscMalloc1(size, &check)); 5468 for (i = 0; i < size; ++i) { 5469 check[i] = -1; 5470 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5471 } 5472 for (i = 0; i < size; ++i) check[perm[i]] = i; 5473 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5474 PetscCall(PetscFree(check)); 5475 } 5476 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5477 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5478 PetscInt *loc_perm; 5479 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5480 for (PetscInt i=0; i<size; i++) { 5481 loc_perm[i] = perm[i]; 5482 loc_perm[size+i] = size + perm[i]; 5483 } 5484 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5485 } 5486 } 5487 PetscFunctionReturn(0); 5488 } 5489 5490 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5491 { 5492 PetscDS prob; 5493 PetscInt depth, Nf, h; 5494 DMLabel label; 5495 5496 PetscFunctionBeginHot; 5497 PetscCall(DMGetDS(dm, &prob)); 5498 Nf = prob->Nf; 5499 label = dm->depthLabel; 5500 *dspace = NULL; 5501 if (field < Nf) { 5502 PetscObject disc = prob->disc[field]; 5503 5504 if (disc->classid == PETSCFE_CLASSID) { 5505 PetscDualSpace dsp; 5506 5507 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5508 PetscCall(DMLabelGetNumValues(label,&depth)); 5509 PetscCall(DMLabelGetValue(label,point,&h)); 5510 h = depth - 1 - h; 5511 if (h) { 5512 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5513 } else { 5514 *dspace = dsp; 5515 } 5516 } 5517 } 5518 PetscFunctionReturn(0); 5519 } 5520 5521 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5522 { 5523 PetscScalar *array; 5524 const PetscScalar *vArray; 5525 const PetscInt *cone, *coneO; 5526 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5527 5528 PetscFunctionBeginHot; 5529 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5530 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5531 PetscCall(DMPlexGetCone(dm, point, &cone)); 5532 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5533 if (!values || !*values) { 5534 if ((point >= pStart) && (point < pEnd)) { 5535 PetscInt dof; 5536 5537 PetscCall(PetscSectionGetDof(section, point, &dof)); 5538 size += dof; 5539 } 5540 for (p = 0; p < numPoints; ++p) { 5541 const PetscInt cp = cone[p]; 5542 PetscInt dof; 5543 5544 if ((cp < pStart) || (cp >= pEnd)) continue; 5545 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5546 size += dof; 5547 } 5548 if (!values) { 5549 if (csize) *csize = size; 5550 PetscFunctionReturn(0); 5551 } 5552 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5553 } else { 5554 array = *values; 5555 } 5556 size = 0; 5557 PetscCall(VecGetArrayRead(v, &vArray)); 5558 if ((point >= pStart) && (point < pEnd)) { 5559 PetscInt dof, off, d; 5560 const PetscScalar *varr; 5561 5562 PetscCall(PetscSectionGetDof(section, point, &dof)); 5563 PetscCall(PetscSectionGetOffset(section, point, &off)); 5564 varr = &vArray[off]; 5565 for (d = 0; d < dof; ++d, ++offset) { 5566 array[offset] = varr[d]; 5567 } 5568 size += dof; 5569 } 5570 for (p = 0; p < numPoints; ++p) { 5571 const PetscInt cp = cone[p]; 5572 PetscInt o = coneO[p]; 5573 PetscInt dof, off, d; 5574 const PetscScalar *varr; 5575 5576 if ((cp < pStart) || (cp >= pEnd)) continue; 5577 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5578 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5579 varr = &vArray[off]; 5580 if (o >= 0) { 5581 for (d = 0; d < dof; ++d, ++offset) { 5582 array[offset] = varr[d]; 5583 } 5584 } else { 5585 for (d = dof-1; d >= 0; --d, ++offset) { 5586 array[offset] = varr[d]; 5587 } 5588 } 5589 size += dof; 5590 } 5591 PetscCall(VecRestoreArrayRead(v, &vArray)); 5592 if (!*values) { 5593 if (csize) *csize = size; 5594 *values = array; 5595 } else { 5596 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5597 *csize = size; 5598 } 5599 PetscFunctionReturn(0); 5600 } 5601 5602 /* Compress out points not in the section */ 5603 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5604 { 5605 const PetscInt np = *numPoints; 5606 PetscInt pStart, pEnd, p, q; 5607 5608 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5609 for (p = 0, q = 0; p < np; ++p) { 5610 const PetscInt r = points[p*2]; 5611 if ((r >= pStart) && (r < pEnd)) { 5612 points[q*2] = r; 5613 points[q*2+1] = points[p*2+1]; 5614 ++q; 5615 } 5616 } 5617 *numPoints = q; 5618 return 0; 5619 } 5620 5621 /* Compressed closure does not apply closure permutation */ 5622 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5623 { 5624 const PetscInt *cla = NULL; 5625 PetscInt np, *pts = NULL; 5626 5627 PetscFunctionBeginHot; 5628 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5629 if (*clPoints) { 5630 PetscInt dof, off; 5631 5632 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5633 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5634 PetscCall(ISGetIndices(*clPoints, &cla)); 5635 np = dof/2; 5636 pts = (PetscInt *) &cla[off]; 5637 } else { 5638 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5639 PetscCall(CompressPoints_Private(section, &np, pts)); 5640 } 5641 *numPoints = np; 5642 *points = pts; 5643 *clp = cla; 5644 PetscFunctionReturn(0); 5645 } 5646 5647 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5648 { 5649 PetscFunctionBeginHot; 5650 if (!*clPoints) { 5651 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5652 } else { 5653 PetscCall(ISRestoreIndices(*clPoints, clp)); 5654 } 5655 *numPoints = 0; 5656 *points = NULL; 5657 *clSec = NULL; 5658 *clPoints = NULL; 5659 *clp = NULL; 5660 PetscFunctionReturn(0); 5661 } 5662 5663 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5664 { 5665 PetscInt offset = 0, p; 5666 const PetscInt **perms = NULL; 5667 const PetscScalar **flips = NULL; 5668 5669 PetscFunctionBeginHot; 5670 *size = 0; 5671 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5672 for (p = 0; p < numPoints; p++) { 5673 const PetscInt point = points[2*p]; 5674 const PetscInt *perm = perms ? perms[p] : NULL; 5675 const PetscScalar *flip = flips ? flips[p] : NULL; 5676 PetscInt dof, off, d; 5677 const PetscScalar *varr; 5678 5679 PetscCall(PetscSectionGetDof(section, point, &dof)); 5680 PetscCall(PetscSectionGetOffset(section, point, &off)); 5681 varr = &vArray[off]; 5682 if (clperm) { 5683 if (perm) { 5684 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5685 } else { 5686 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5687 } 5688 if (flip) { 5689 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5690 } 5691 } else { 5692 if (perm) { 5693 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5694 } else { 5695 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5696 } 5697 if (flip) { 5698 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5699 } 5700 } 5701 offset += dof; 5702 } 5703 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5704 *size = offset; 5705 PetscFunctionReturn(0); 5706 } 5707 5708 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[]) 5709 { 5710 PetscInt offset = 0, f; 5711 5712 PetscFunctionBeginHot; 5713 *size = 0; 5714 for (f = 0; f < numFields; ++f) { 5715 PetscInt p; 5716 const PetscInt **perms = NULL; 5717 const PetscScalar **flips = NULL; 5718 5719 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5720 for (p = 0; p < numPoints; p++) { 5721 const PetscInt point = points[2*p]; 5722 PetscInt fdof, foff, b; 5723 const PetscScalar *varr; 5724 const PetscInt *perm = perms ? perms[p] : NULL; 5725 const PetscScalar *flip = flips ? flips[p] : NULL; 5726 5727 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5728 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5729 varr = &vArray[foff]; 5730 if (clperm) { 5731 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5732 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5733 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5734 } else { 5735 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5736 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5737 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5738 } 5739 offset += fdof; 5740 } 5741 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5742 } 5743 *size = offset; 5744 PetscFunctionReturn(0); 5745 } 5746 5747 /*@C 5748 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5749 5750 Not collective 5751 5752 Input Parameters: 5753 + dm - The DM 5754 . section - The section describing the layout in v, or NULL to use the default section 5755 . v - The local vector 5756 - point - The point in the DM 5757 5758 Input/Output Parameters: 5759 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5760 - values - An array to use for the values, or NULL to have it allocated automatically; 5761 if the user provided NULL, it is a borrowed array and should not be freed 5762 5763 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5764 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5765 $ assembly function, and a user may already have allocated storage for this operation. 5766 $ 5767 $ A typical use could be 5768 $ 5769 $ values = NULL; 5770 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5771 $ for (cl = 0; cl < clSize; ++cl) { 5772 $ <Compute on closure> 5773 $ } 5774 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5775 $ 5776 $ or 5777 $ 5778 $ PetscMalloc1(clMaxSize, &values); 5779 $ for (p = pStart; p < pEnd; ++p) { 5780 $ clSize = clMaxSize; 5781 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5782 $ for (cl = 0; cl < clSize; ++cl) { 5783 $ <Compute on closure> 5784 $ } 5785 $ } 5786 $ PetscFree(values); 5787 5788 Fortran Notes: 5789 Since it returns an array, this routine is only available in Fortran 90, and you must 5790 include petsc.h90 in your code. 5791 5792 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5793 5794 Level: intermediate 5795 5796 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5797 @*/ 5798 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5799 { 5800 PetscSection clSection; 5801 IS clPoints; 5802 PetscInt *points = NULL; 5803 const PetscInt *clp, *perm; 5804 PetscInt depth, numFields, numPoints, asize; 5805 5806 PetscFunctionBeginHot; 5807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5808 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5809 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5810 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5811 PetscCall(DMPlexGetDepth(dm, &depth)); 5812 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5813 if (depth == 1 && numFields < 2) { 5814 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5815 PetscFunctionReturn(0); 5816 } 5817 /* Get points */ 5818 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5819 /* Get sizes */ 5820 asize = 0; 5821 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5822 PetscInt dof; 5823 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5824 asize += dof; 5825 } 5826 if (values) { 5827 const PetscScalar *vArray; 5828 PetscInt size; 5829 5830 if (*values) { 5831 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); 5832 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5833 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5834 PetscCall(VecGetArrayRead(v, &vArray)); 5835 /* Get values */ 5836 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5837 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5838 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5839 /* Cleanup array */ 5840 PetscCall(VecRestoreArrayRead(v, &vArray)); 5841 } 5842 if (csize) *csize = asize; 5843 /* Cleanup points */ 5844 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5845 PetscFunctionReturn(0); 5846 } 5847 5848 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5849 { 5850 DMLabel depthLabel; 5851 PetscSection clSection; 5852 IS clPoints; 5853 PetscScalar *array; 5854 const PetscScalar *vArray; 5855 PetscInt *points = NULL; 5856 const PetscInt *clp, *perm = NULL; 5857 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5858 5859 PetscFunctionBeginHot; 5860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5861 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5862 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5863 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5864 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5865 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5866 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5867 if (mdepth == 1 && numFields < 2) { 5868 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5869 PetscFunctionReturn(0); 5870 } 5871 /* Get points */ 5872 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5873 for (clsize=0,p=0; p<Np; p++) { 5874 PetscInt dof; 5875 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5876 clsize += dof; 5877 } 5878 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5879 /* Filter points */ 5880 for (p = 0; p < numPoints*2; p += 2) { 5881 PetscInt dep; 5882 5883 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5884 if (dep != depth) continue; 5885 points[Np*2+0] = points[p]; 5886 points[Np*2+1] = points[p+1]; 5887 ++Np; 5888 } 5889 /* Get array */ 5890 if (!values || !*values) { 5891 PetscInt asize = 0, dof; 5892 5893 for (p = 0; p < Np*2; p += 2) { 5894 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5895 asize += dof; 5896 } 5897 if (!values) { 5898 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5899 if (csize) *csize = asize; 5900 PetscFunctionReturn(0); 5901 } 5902 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5903 } else { 5904 array = *values; 5905 } 5906 PetscCall(VecGetArrayRead(v, &vArray)); 5907 /* Get values */ 5908 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5909 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5910 /* Cleanup points */ 5911 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5912 /* Cleanup array */ 5913 PetscCall(VecRestoreArrayRead(v, &vArray)); 5914 if (!*values) { 5915 if (csize) *csize = size; 5916 *values = array; 5917 } else { 5918 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5919 *csize = size; 5920 } 5921 PetscFunctionReturn(0); 5922 } 5923 5924 /*@C 5925 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5926 5927 Not collective 5928 5929 Input Parameters: 5930 + dm - The DM 5931 . section - The section describing the layout in v, or NULL to use the default section 5932 . v - The local vector 5933 . point - The point in the DM 5934 . csize - The number of values in the closure, or NULL 5935 - values - The array of values, which is a borrowed array and should not be freed 5936 5937 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5938 5939 Fortran Notes: 5940 Since it returns an array, this routine is only available in Fortran 90, and you must 5941 include petsc.h90 in your code. 5942 5943 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5944 5945 Level: intermediate 5946 5947 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5948 @*/ 5949 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5950 { 5951 PetscInt size = 0; 5952 5953 PetscFunctionBegin; 5954 /* Should work without recalculating size */ 5955 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5956 *values = NULL; 5957 PetscFunctionReturn(0); 5958 } 5959 5960 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5961 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5962 5963 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[]) 5964 { 5965 PetscInt cdof; /* The number of constraints on this point */ 5966 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5967 PetscScalar *a; 5968 PetscInt off, cind = 0, k; 5969 5970 PetscFunctionBegin; 5971 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5972 PetscCall(PetscSectionGetOffset(section, point, &off)); 5973 a = &array[off]; 5974 if (!cdof || setBC) { 5975 if (clperm) { 5976 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5977 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5978 } else { 5979 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5980 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5981 } 5982 } else { 5983 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5984 if (clperm) { 5985 if (perm) {for (k = 0; k < dof; ++k) { 5986 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5987 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5988 } 5989 } else { 5990 for (k = 0; k < dof; ++k) { 5991 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5992 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5993 } 5994 } 5995 } else { 5996 if (perm) { 5997 for (k = 0; k < dof; ++k) { 5998 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5999 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6000 } 6001 } else { 6002 for (k = 0; k < dof; ++k) { 6003 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6004 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6005 } 6006 } 6007 } 6008 } 6009 PetscFunctionReturn(0); 6010 } 6011 6012 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[]) 6013 { 6014 PetscInt cdof; /* The number of constraints on this point */ 6015 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6016 PetscScalar *a; 6017 PetscInt off, cind = 0, k; 6018 6019 PetscFunctionBegin; 6020 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6021 PetscCall(PetscSectionGetOffset(section, point, &off)); 6022 a = &array[off]; 6023 if (cdof) { 6024 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6025 if (clperm) { 6026 if (perm) { 6027 for (k = 0; k < dof; ++k) { 6028 if ((cind < cdof) && (k == cdofs[cind])) { 6029 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6030 cind++; 6031 } 6032 } 6033 } else { 6034 for (k = 0; k < dof; ++k) { 6035 if ((cind < cdof) && (k == cdofs[cind])) { 6036 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6037 cind++; 6038 } 6039 } 6040 } 6041 } else { 6042 if (perm) { 6043 for (k = 0; k < dof; ++k) { 6044 if ((cind < cdof) && (k == cdofs[cind])) { 6045 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6046 cind++; 6047 } 6048 } 6049 } else { 6050 for (k = 0; k < dof; ++k) { 6051 if ((cind < cdof) && (k == cdofs[cind])) { 6052 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6053 cind++; 6054 } 6055 } 6056 } 6057 } 6058 } 6059 PetscFunctionReturn(0); 6060 } 6061 6062 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[]) 6063 { 6064 PetscScalar *a; 6065 PetscInt fdof, foff, fcdof, foffset = *offset; 6066 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6067 PetscInt cind = 0, b; 6068 6069 PetscFunctionBegin; 6070 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6071 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6072 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6073 a = &array[foff]; 6074 if (!fcdof || setBC) { 6075 if (clperm) { 6076 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6077 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6078 } else { 6079 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6080 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6081 } 6082 } else { 6083 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6084 if (clperm) { 6085 if (perm) { 6086 for (b = 0; b < fdof; b++) { 6087 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6088 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6089 } 6090 } else { 6091 for (b = 0; b < fdof; b++) { 6092 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6093 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6094 } 6095 } 6096 } else { 6097 if (perm) { 6098 for (b = 0; b < fdof; b++) { 6099 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6100 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6101 } 6102 } else { 6103 for (b = 0; b < fdof; b++) { 6104 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6105 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6106 } 6107 } 6108 } 6109 } 6110 *offset += fdof; 6111 PetscFunctionReturn(0); 6112 } 6113 6114 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[]) 6115 { 6116 PetscScalar *a; 6117 PetscInt fdof, foff, fcdof, foffset = *offset; 6118 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6119 PetscInt Nc, cind = 0, ncind = 0, b; 6120 PetscBool ncSet, fcSet; 6121 6122 PetscFunctionBegin; 6123 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6124 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6125 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6126 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6127 a = &array[foff]; 6128 if (fcdof) { 6129 /* We just override fcdof and fcdofs with Ncc and comps */ 6130 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6131 if (clperm) { 6132 if (perm) { 6133 if (comps) { 6134 for (b = 0; b < fdof; b++) { 6135 ncSet = fcSet = PETSC_FALSE; 6136 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6137 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6138 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6139 } 6140 } else { 6141 for (b = 0; b < fdof; b++) { 6142 if ((cind < fcdof) && (b == fcdofs[cind])) { 6143 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6144 ++cind; 6145 } 6146 } 6147 } 6148 } else { 6149 if (comps) { 6150 for (b = 0; b < fdof; b++) { 6151 ncSet = fcSet = PETSC_FALSE; 6152 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6153 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6154 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6155 } 6156 } else { 6157 for (b = 0; b < fdof; b++) { 6158 if ((cind < fcdof) && (b == fcdofs[cind])) { 6159 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6160 ++cind; 6161 } 6162 } 6163 } 6164 } 6165 } else { 6166 if (perm) { 6167 if (comps) { 6168 for (b = 0; b < fdof; b++) { 6169 ncSet = fcSet = PETSC_FALSE; 6170 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6171 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6172 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6173 } 6174 } else { 6175 for (b = 0; b < fdof; b++) { 6176 if ((cind < fcdof) && (b == fcdofs[cind])) { 6177 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6178 ++cind; 6179 } 6180 } 6181 } 6182 } else { 6183 if (comps) { 6184 for (b = 0; b < fdof; b++) { 6185 ncSet = fcSet = PETSC_FALSE; 6186 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6187 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6188 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6189 } 6190 } else { 6191 for (b = 0; b < fdof; b++) { 6192 if ((cind < fcdof) && (b == fcdofs[cind])) { 6193 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6194 ++cind; 6195 } 6196 } 6197 } 6198 } 6199 } 6200 } 6201 *offset += fdof; 6202 PetscFunctionReturn(0); 6203 } 6204 6205 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6206 { 6207 PetscScalar *array; 6208 const PetscInt *cone, *coneO; 6209 PetscInt pStart, pEnd, p, numPoints, off, dof; 6210 6211 PetscFunctionBeginHot; 6212 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6213 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6214 PetscCall(DMPlexGetCone(dm, point, &cone)); 6215 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6216 PetscCall(VecGetArray(v, &array)); 6217 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6218 const PetscInt cp = !p ? point : cone[p-1]; 6219 const PetscInt o = !p ? 0 : coneO[p-1]; 6220 6221 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6222 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6223 /* ADD_VALUES */ 6224 { 6225 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6226 PetscScalar *a; 6227 PetscInt cdof, coff, cind = 0, k; 6228 6229 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6230 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6231 a = &array[coff]; 6232 if (!cdof) { 6233 if (o >= 0) { 6234 for (k = 0; k < dof; ++k) { 6235 a[k] += values[off+k]; 6236 } 6237 } else { 6238 for (k = 0; k < dof; ++k) { 6239 a[k] += values[off+dof-k-1]; 6240 } 6241 } 6242 } else { 6243 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6244 if (o >= 0) { 6245 for (k = 0; k < dof; ++k) { 6246 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6247 a[k] += values[off+k]; 6248 } 6249 } else { 6250 for (k = 0; k < dof; ++k) { 6251 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6252 a[k] += values[off+dof-k-1]; 6253 } 6254 } 6255 } 6256 } 6257 } 6258 PetscCall(VecRestoreArray(v, &array)); 6259 PetscFunctionReturn(0); 6260 } 6261 6262 /*@C 6263 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6264 6265 Not collective 6266 6267 Input Parameters: 6268 + dm - The DM 6269 . section - The section describing the layout in v, or NULL to use the default section 6270 . v - The local vector 6271 . point - The point in the DM 6272 . values - The array of values 6273 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6274 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6275 6276 Fortran Notes: 6277 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6278 6279 Level: intermediate 6280 6281 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6282 @*/ 6283 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6284 { 6285 PetscSection clSection; 6286 IS clPoints; 6287 PetscScalar *array; 6288 PetscInt *points = NULL; 6289 const PetscInt *clp, *clperm = NULL; 6290 PetscInt depth, numFields, numPoints, p, clsize; 6291 6292 PetscFunctionBeginHot; 6293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6294 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6295 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6296 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6297 PetscCall(DMPlexGetDepth(dm, &depth)); 6298 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6299 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6300 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6301 PetscFunctionReturn(0); 6302 } 6303 /* Get points */ 6304 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6305 for (clsize=0,p=0; p<numPoints; p++) { 6306 PetscInt dof; 6307 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6308 clsize += dof; 6309 } 6310 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6311 /* Get array */ 6312 PetscCall(VecGetArray(v, &array)); 6313 /* Get values */ 6314 if (numFields > 0) { 6315 PetscInt offset = 0, f; 6316 for (f = 0; f < numFields; ++f) { 6317 const PetscInt **perms = NULL; 6318 const PetscScalar **flips = NULL; 6319 6320 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6321 switch (mode) { 6322 case INSERT_VALUES: 6323 for (p = 0; p < numPoints; p++) { 6324 const PetscInt point = points[2*p]; 6325 const PetscInt *perm = perms ? perms[p] : NULL; 6326 const PetscScalar *flip = flips ? flips[p] : NULL; 6327 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6328 } break; 6329 case INSERT_ALL_VALUES: 6330 for (p = 0; p < numPoints; p++) { 6331 const PetscInt point = points[2*p]; 6332 const PetscInt *perm = perms ? perms[p] : NULL; 6333 const PetscScalar *flip = flips ? flips[p] : NULL; 6334 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6335 } break; 6336 case INSERT_BC_VALUES: 6337 for (p = 0; p < numPoints; p++) { 6338 const PetscInt point = points[2*p]; 6339 const PetscInt *perm = perms ? perms[p] : NULL; 6340 const PetscScalar *flip = flips ? flips[p] : NULL; 6341 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6342 } break; 6343 case ADD_VALUES: 6344 for (p = 0; p < numPoints; p++) { 6345 const PetscInt point = points[2*p]; 6346 const PetscInt *perm = perms ? perms[p] : NULL; 6347 const PetscScalar *flip = flips ? flips[p] : NULL; 6348 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6349 } break; 6350 case ADD_ALL_VALUES: 6351 for (p = 0; p < numPoints; p++) { 6352 const PetscInt point = points[2*p]; 6353 const PetscInt *perm = perms ? perms[p] : NULL; 6354 const PetscScalar *flip = flips ? flips[p] : NULL; 6355 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6356 } break; 6357 case ADD_BC_VALUES: 6358 for (p = 0; p < numPoints; p++) { 6359 const PetscInt point = points[2*p]; 6360 const PetscInt *perm = perms ? perms[p] : NULL; 6361 const PetscScalar *flip = flips ? flips[p] : NULL; 6362 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6363 } break; 6364 default: 6365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6366 } 6367 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6368 } 6369 } else { 6370 PetscInt dof, off; 6371 const PetscInt **perms = NULL; 6372 const PetscScalar **flips = NULL; 6373 6374 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6375 switch (mode) { 6376 case INSERT_VALUES: 6377 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6378 const PetscInt point = points[2*p]; 6379 const PetscInt *perm = perms ? perms[p] : NULL; 6380 const PetscScalar *flip = flips ? flips[p] : NULL; 6381 PetscCall(PetscSectionGetDof(section, point, &dof)); 6382 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6383 } break; 6384 case INSERT_ALL_VALUES: 6385 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6386 const PetscInt point = points[2*p]; 6387 const PetscInt *perm = perms ? perms[p] : NULL; 6388 const PetscScalar *flip = flips ? flips[p] : NULL; 6389 PetscCall(PetscSectionGetDof(section, point, &dof)); 6390 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6391 } break; 6392 case INSERT_BC_VALUES: 6393 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6394 const PetscInt point = points[2*p]; 6395 const PetscInt *perm = perms ? perms[p] : NULL; 6396 const PetscScalar *flip = flips ? flips[p] : NULL; 6397 PetscCall(PetscSectionGetDof(section, point, &dof)); 6398 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6399 } break; 6400 case ADD_VALUES: 6401 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6402 const PetscInt point = points[2*p]; 6403 const PetscInt *perm = perms ? perms[p] : NULL; 6404 const PetscScalar *flip = flips ? flips[p] : NULL; 6405 PetscCall(PetscSectionGetDof(section, point, &dof)); 6406 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6407 } break; 6408 case ADD_ALL_VALUES: 6409 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6410 const PetscInt point = points[2*p]; 6411 const PetscInt *perm = perms ? perms[p] : NULL; 6412 const PetscScalar *flip = flips ? flips[p] : NULL; 6413 PetscCall(PetscSectionGetDof(section, point, &dof)); 6414 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6415 } break; 6416 case ADD_BC_VALUES: 6417 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6418 const PetscInt point = points[2*p]; 6419 const PetscInt *perm = perms ? perms[p] : NULL; 6420 const PetscScalar *flip = flips ? flips[p] : NULL; 6421 PetscCall(PetscSectionGetDof(section, point, &dof)); 6422 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6423 } break; 6424 default: 6425 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6426 } 6427 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6428 } 6429 /* Cleanup points */ 6430 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6431 /* Cleanup array */ 6432 PetscCall(VecRestoreArray(v, &array)); 6433 PetscFunctionReturn(0); 6434 } 6435 6436 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6437 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6438 { 6439 PetscFunctionBegin; 6440 if (label) { 6441 PetscBool contains; 6442 PetscInt fdof; 6443 6444 PetscCall(DMLabelStratumHasPoint(label, labelId, point, &contains)); 6445 if (!contains) { 6446 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6447 *offset += fdof; 6448 PetscFunctionReturn(1); 6449 } 6450 } 6451 PetscFunctionReturn(0); 6452 } 6453 6454 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6455 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) 6456 { 6457 PetscSection clSection; 6458 IS clPoints; 6459 PetscScalar *array; 6460 PetscInt *points = NULL; 6461 const PetscInt *clp; 6462 PetscInt numFields, numPoints, p; 6463 PetscInt offset = 0, f; 6464 6465 PetscFunctionBeginHot; 6466 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6467 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6468 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6469 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6470 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6471 /* Get points */ 6472 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6473 /* Get array */ 6474 PetscCall(VecGetArray(v, &array)); 6475 /* Get values */ 6476 for (f = 0; f < numFields; ++f) { 6477 const PetscInt **perms = NULL; 6478 const PetscScalar **flips = NULL; 6479 6480 if (!fieldActive[f]) { 6481 for (p = 0; p < numPoints*2; p += 2) { 6482 PetscInt fdof; 6483 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6484 offset += fdof; 6485 } 6486 continue; 6487 } 6488 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6489 switch (mode) { 6490 case INSERT_VALUES: 6491 for (p = 0; p < numPoints; p++) { 6492 const PetscInt point = points[2*p]; 6493 const PetscInt *perm = perms ? perms[p] : NULL; 6494 const PetscScalar *flip = flips ? flips[p] : NULL; 6495 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6496 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6497 } break; 6498 case INSERT_ALL_VALUES: 6499 for (p = 0; p < numPoints; p++) { 6500 const PetscInt point = points[2*p]; 6501 const PetscInt *perm = perms ? perms[p] : NULL; 6502 const PetscScalar *flip = flips ? flips[p] : NULL; 6503 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6504 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6505 } break; 6506 case INSERT_BC_VALUES: 6507 for (p = 0; p < numPoints; p++) { 6508 const PetscInt point = points[2*p]; 6509 const PetscInt *perm = perms ? perms[p] : NULL; 6510 const PetscScalar *flip = flips ? flips[p] : NULL; 6511 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6512 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6513 } break; 6514 case ADD_VALUES: 6515 for (p = 0; p < numPoints; p++) { 6516 const PetscInt point = points[2*p]; 6517 const PetscInt *perm = perms ? perms[p] : NULL; 6518 const PetscScalar *flip = flips ? flips[p] : NULL; 6519 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6520 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6521 } break; 6522 case ADD_ALL_VALUES: 6523 for (p = 0; p < numPoints; p++) { 6524 const PetscInt point = points[2*p]; 6525 const PetscInt *perm = perms ? perms[p] : NULL; 6526 const PetscScalar *flip = flips ? flips[p] : NULL; 6527 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6528 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6529 } break; 6530 default: 6531 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6532 } 6533 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6534 } 6535 /* Cleanup points */ 6536 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6537 /* Cleanup array */ 6538 PetscCall(VecRestoreArray(v, &array)); 6539 PetscFunctionReturn(0); 6540 } 6541 6542 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6543 { 6544 PetscMPIInt rank; 6545 PetscInt i, j; 6546 6547 PetscFunctionBegin; 6548 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6549 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6550 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6551 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6552 numCIndices = numCIndices ? numCIndices : numRIndices; 6553 if (!values) PetscFunctionReturn(0); 6554 for (i = 0; i < numRIndices; i++) { 6555 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6556 for (j = 0; j < numCIndices; j++) { 6557 #if defined(PETSC_USE_COMPLEX) 6558 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6559 #else 6560 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6561 #endif 6562 } 6563 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6564 } 6565 PetscFunctionReturn(0); 6566 } 6567 6568 /* 6569 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6570 6571 Input Parameters: 6572 + section - The section for this data layout 6573 . islocal - Is the section (and thus indices being requested) local or global? 6574 . point - The point contributing dofs with these indices 6575 . off - The global offset of this point 6576 . loff - The local offset of each field 6577 . setBC - The flag determining whether to include indices of boundary values 6578 . perm - A permutation of the dofs on this point, or NULL 6579 - indperm - A permutation of the entire indices array, or NULL 6580 6581 Output Parameter: 6582 . indices - Indices for dofs on this point 6583 6584 Level: developer 6585 6586 Note: The indices could be local or global, depending on the value of 'off'. 6587 */ 6588 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6589 { 6590 PetscInt dof; /* The number of unknowns on this point */ 6591 PetscInt cdof; /* The number of constraints on this point */ 6592 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6593 PetscInt cind = 0, k; 6594 6595 PetscFunctionBegin; 6596 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6597 PetscCall(PetscSectionGetDof(section, point, &dof)); 6598 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6599 if (!cdof || setBC) { 6600 for (k = 0; k < dof; ++k) { 6601 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6602 const PetscInt ind = indperm ? indperm[preind] : preind; 6603 6604 indices[ind] = off + k; 6605 } 6606 } else { 6607 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6608 for (k = 0; k < dof; ++k) { 6609 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6610 const PetscInt ind = indperm ? indperm[preind] : preind; 6611 6612 if ((cind < cdof) && (k == cdofs[cind])) { 6613 /* Insert check for returning constrained indices */ 6614 indices[ind] = -(off+k+1); 6615 ++cind; 6616 } else { 6617 indices[ind] = off + k - (islocal ? 0 : cind); 6618 } 6619 } 6620 } 6621 *loff += dof; 6622 PetscFunctionReturn(0); 6623 } 6624 6625 /* 6626 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6627 6628 Input Parameters: 6629 + section - a section (global or local) 6630 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6631 . point - point within section 6632 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6633 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6634 . setBC - identify constrained (boundary condition) points via involution. 6635 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6636 . permsoff - offset 6637 - indperm - index permutation 6638 6639 Output Parameter: 6640 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6641 . indices - array to hold indices (as defined by section) of each dof associated with point 6642 6643 Notes: 6644 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6645 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6646 in the local vector. 6647 6648 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6649 significant). It is invalid to call with a global section and setBC=true. 6650 6651 Developer Note: 6652 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6653 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6654 offset could be obtained from the section instead of passing it explicitly as we do now. 6655 6656 Example: 6657 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6658 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6659 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6660 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. 6661 6662 Level: developer 6663 */ 6664 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[]) 6665 { 6666 PetscInt numFields, foff, f; 6667 6668 PetscFunctionBegin; 6669 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6670 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6671 for (f = 0, foff = 0; f < numFields; ++f) { 6672 PetscInt fdof, cfdof; 6673 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6674 PetscInt cind = 0, b; 6675 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6676 6677 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6678 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6679 if (!cfdof || setBC) { 6680 for (b = 0; b < fdof; ++b) { 6681 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6682 const PetscInt ind = indperm ? indperm[preind] : preind; 6683 6684 indices[ind] = off+foff+b; 6685 } 6686 } else { 6687 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6688 for (b = 0; b < fdof; ++b) { 6689 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6690 const PetscInt ind = indperm ? indperm[preind] : preind; 6691 6692 if ((cind < cfdof) && (b == fcdofs[cind])) { 6693 indices[ind] = -(off+foff+b+1); 6694 ++cind; 6695 } else { 6696 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6697 } 6698 } 6699 } 6700 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6701 foffs[f] += fdof; 6702 } 6703 PetscFunctionReturn(0); 6704 } 6705 6706 /* 6707 This version believes the globalSection offsets for each field, rather than just the point offset 6708 6709 . foffs - The offset into 'indices' for each field, since it is segregated by field 6710 6711 Notes: 6712 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6713 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6714 */ 6715 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6716 { 6717 PetscInt numFields, foff, f; 6718 6719 PetscFunctionBegin; 6720 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6721 for (f = 0; f < numFields; ++f) { 6722 PetscInt fdof, cfdof; 6723 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6724 PetscInt cind = 0, b; 6725 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6726 6727 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6728 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6729 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6730 if (!cfdof) { 6731 for (b = 0; b < fdof; ++b) { 6732 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6733 const PetscInt ind = indperm ? indperm[preind] : preind; 6734 6735 indices[ind] = foff+b; 6736 } 6737 } else { 6738 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6739 for (b = 0; b < fdof; ++b) { 6740 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6741 const PetscInt ind = indperm ? indperm[preind] : preind; 6742 6743 if ((cind < cfdof) && (b == fcdofs[cind])) { 6744 indices[ind] = -(foff+b+1); 6745 ++cind; 6746 } else { 6747 indices[ind] = foff+b-cind; 6748 } 6749 } 6750 } 6751 foffs[f] += fdof; 6752 } 6753 PetscFunctionReturn(0); 6754 } 6755 6756 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) 6757 { 6758 Mat cMat; 6759 PetscSection aSec, cSec; 6760 IS aIS; 6761 PetscInt aStart = -1, aEnd = -1; 6762 const PetscInt *anchors; 6763 PetscInt numFields, f, p, q, newP = 0; 6764 PetscInt newNumPoints = 0, newNumIndices = 0; 6765 PetscInt *newPoints, *indices, *newIndices; 6766 PetscInt maxAnchor, maxDof; 6767 PetscInt newOffsets[32]; 6768 PetscInt *pointMatOffsets[32]; 6769 PetscInt *newPointOffsets[32]; 6770 PetscScalar *pointMat[32]; 6771 PetscScalar *newValues=NULL,*tmpValues; 6772 PetscBool anyConstrained = PETSC_FALSE; 6773 6774 PetscFunctionBegin; 6775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6776 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6777 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6778 6779 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6780 /* if there are point-to-point constraints */ 6781 if (aSec) { 6782 PetscCall(PetscArrayzero(newOffsets, 32)); 6783 PetscCall(ISGetIndices(aIS,&anchors)); 6784 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6785 /* figure out how many points are going to be in the new element matrix 6786 * (we allow double counting, because it's all just going to be summed 6787 * into the global matrix anyway) */ 6788 for (p = 0; p < 2*numPoints; p+=2) { 6789 PetscInt b = points[p]; 6790 PetscInt bDof = 0, bSecDof; 6791 6792 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6793 if (!bSecDof) { 6794 continue; 6795 } 6796 if (b >= aStart && b < aEnd) { 6797 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6798 } 6799 if (bDof) { 6800 /* this point is constrained */ 6801 /* it is going to be replaced by its anchors */ 6802 PetscInt bOff, q; 6803 6804 anyConstrained = PETSC_TRUE; 6805 newNumPoints += bDof; 6806 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6807 for (q = 0; q < bDof; q++) { 6808 PetscInt a = anchors[bOff + q]; 6809 PetscInt aDof; 6810 6811 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6812 newNumIndices += aDof; 6813 for (f = 0; f < numFields; ++f) { 6814 PetscInt fDof; 6815 6816 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6817 newOffsets[f+1] += fDof; 6818 } 6819 } 6820 } 6821 else { 6822 /* this point is not constrained */ 6823 newNumPoints++; 6824 newNumIndices += bSecDof; 6825 for (f = 0; f < numFields; ++f) { 6826 PetscInt fDof; 6827 6828 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6829 newOffsets[f+1] += fDof; 6830 } 6831 } 6832 } 6833 } 6834 if (!anyConstrained) { 6835 if (outNumPoints) *outNumPoints = 0; 6836 if (outNumIndices) *outNumIndices = 0; 6837 if (outPoints) *outPoints = NULL; 6838 if (outValues) *outValues = NULL; 6839 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6840 PetscFunctionReturn(0); 6841 } 6842 6843 if (outNumPoints) *outNumPoints = newNumPoints; 6844 if (outNumIndices) *outNumIndices = newNumIndices; 6845 6846 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6847 6848 if (!outPoints && !outValues) { 6849 if (offsets) { 6850 for (f = 0; f <= numFields; f++) { 6851 offsets[f] = newOffsets[f]; 6852 } 6853 } 6854 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6855 PetscFunctionReturn(0); 6856 } 6857 6858 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6859 6860 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6861 6862 /* workspaces */ 6863 if (numFields) { 6864 for (f = 0; f < numFields; f++) { 6865 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6866 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6867 } 6868 } 6869 else { 6870 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6871 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6872 } 6873 6874 /* get workspaces for the point-to-point matrices */ 6875 if (numFields) { 6876 PetscInt totalOffset, totalMatOffset; 6877 6878 for (p = 0; p < numPoints; p++) { 6879 PetscInt b = points[2*p]; 6880 PetscInt bDof = 0, bSecDof; 6881 6882 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6883 if (!bSecDof) { 6884 for (f = 0; f < numFields; f++) { 6885 newPointOffsets[f][p + 1] = 0; 6886 pointMatOffsets[f][p + 1] = 0; 6887 } 6888 continue; 6889 } 6890 if (b >= aStart && b < aEnd) { 6891 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6892 } 6893 if (bDof) { 6894 for (f = 0; f < numFields; f++) { 6895 PetscInt fDof, q, bOff, allFDof = 0; 6896 6897 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6898 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6899 for (q = 0; q < bDof; q++) { 6900 PetscInt a = anchors[bOff + q]; 6901 PetscInt aFDof; 6902 6903 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6904 allFDof += aFDof; 6905 } 6906 newPointOffsets[f][p+1] = allFDof; 6907 pointMatOffsets[f][p+1] = fDof * allFDof; 6908 } 6909 } 6910 else { 6911 for (f = 0; f < numFields; f++) { 6912 PetscInt fDof; 6913 6914 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6915 newPointOffsets[f][p+1] = fDof; 6916 pointMatOffsets[f][p+1] = 0; 6917 } 6918 } 6919 } 6920 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6921 newPointOffsets[f][0] = totalOffset; 6922 pointMatOffsets[f][0] = totalMatOffset; 6923 for (p = 0; p < numPoints; p++) { 6924 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6925 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6926 } 6927 totalOffset = newPointOffsets[f][numPoints]; 6928 totalMatOffset = pointMatOffsets[f][numPoints]; 6929 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6930 } 6931 } 6932 else { 6933 for (p = 0; p < numPoints; p++) { 6934 PetscInt b = points[2*p]; 6935 PetscInt bDof = 0, bSecDof; 6936 6937 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6938 if (!bSecDof) { 6939 newPointOffsets[0][p + 1] = 0; 6940 pointMatOffsets[0][p + 1] = 0; 6941 continue; 6942 } 6943 if (b >= aStart && b < aEnd) { 6944 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6945 } 6946 if (bDof) { 6947 PetscInt bOff, q, allDof = 0; 6948 6949 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6950 for (q = 0; q < bDof; q++) { 6951 PetscInt a = anchors[bOff + q], aDof; 6952 6953 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6954 allDof += aDof; 6955 } 6956 newPointOffsets[0][p+1] = allDof; 6957 pointMatOffsets[0][p+1] = bSecDof * allDof; 6958 } 6959 else { 6960 newPointOffsets[0][p+1] = bSecDof; 6961 pointMatOffsets[0][p+1] = 0; 6962 } 6963 } 6964 newPointOffsets[0][0] = 0; 6965 pointMatOffsets[0][0] = 0; 6966 for (p = 0; p < numPoints; p++) { 6967 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6968 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6969 } 6970 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6971 } 6972 6973 /* output arrays */ 6974 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6975 6976 /* get the point-to-point matrices; construct newPoints */ 6977 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6978 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6979 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6980 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6981 if (numFields) { 6982 for (p = 0, newP = 0; p < numPoints; p++) { 6983 PetscInt b = points[2*p]; 6984 PetscInt o = points[2*p+1]; 6985 PetscInt bDof = 0, bSecDof; 6986 6987 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6988 if (!bSecDof) { 6989 continue; 6990 } 6991 if (b >= aStart && b < aEnd) { 6992 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6993 } 6994 if (bDof) { 6995 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6996 6997 fStart[0] = 0; 6998 fEnd[0] = 0; 6999 for (f = 0; f < numFields; f++) { 7000 PetscInt fDof; 7001 7002 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7003 fStart[f+1] = fStart[f] + fDof; 7004 fEnd[f+1] = fStart[f+1]; 7005 } 7006 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7007 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7008 7009 fAnchorStart[0] = 0; 7010 fAnchorEnd[0] = 0; 7011 for (f = 0; f < numFields; f++) { 7012 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7013 7014 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7015 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7016 } 7017 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7018 for (q = 0; q < bDof; q++) { 7019 PetscInt a = anchors[bOff + q], aOff; 7020 7021 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7022 newPoints[2*(newP + q)] = a; 7023 newPoints[2*(newP + q) + 1] = 0; 7024 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7025 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7026 } 7027 newP += bDof; 7028 7029 if (outValues) { 7030 /* get the point-to-point submatrix */ 7031 for (f = 0; f < numFields; f++) { 7032 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7033 } 7034 } 7035 } 7036 else { 7037 newPoints[2 * newP] = b; 7038 newPoints[2 * newP + 1] = o; 7039 newP++; 7040 } 7041 } 7042 } else { 7043 for (p = 0; p < numPoints; p++) { 7044 PetscInt b = points[2*p]; 7045 PetscInt o = points[2*p+1]; 7046 PetscInt bDof = 0, bSecDof; 7047 7048 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7049 if (!bSecDof) { 7050 continue; 7051 } 7052 if (b >= aStart && b < aEnd) { 7053 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7054 } 7055 if (bDof) { 7056 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7057 7058 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7059 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7060 7061 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7062 for (q = 0; q < bDof; q++) { 7063 PetscInt a = anchors[bOff + q], aOff; 7064 7065 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7066 7067 newPoints[2*(newP + q)] = a; 7068 newPoints[2*(newP + q) + 1] = 0; 7069 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7070 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7071 } 7072 newP += bDof; 7073 7074 /* get the point-to-point submatrix */ 7075 if (outValues) { 7076 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7077 } 7078 } 7079 else { 7080 newPoints[2 * newP] = b; 7081 newPoints[2 * newP + 1] = o; 7082 newP++; 7083 } 7084 } 7085 } 7086 7087 if (outValues) { 7088 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7089 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7090 /* multiply constraints on the right */ 7091 if (numFields) { 7092 for (f = 0; f < numFields; f++) { 7093 PetscInt oldOff = offsets[f]; 7094 7095 for (p = 0; p < numPoints; p++) { 7096 PetscInt cStart = newPointOffsets[f][p]; 7097 PetscInt b = points[2 * p]; 7098 PetscInt c, r, k; 7099 PetscInt dof; 7100 7101 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7102 if (!dof) { 7103 continue; 7104 } 7105 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7106 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7107 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7108 7109 for (r = 0; r < numIndices; r++) { 7110 for (c = 0; c < nCols; c++) { 7111 for (k = 0; k < dof; k++) { 7112 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7113 } 7114 } 7115 } 7116 } 7117 else { 7118 /* copy this column as is */ 7119 for (r = 0; r < numIndices; r++) { 7120 for (c = 0; c < dof; c++) { 7121 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7122 } 7123 } 7124 } 7125 oldOff += dof; 7126 } 7127 } 7128 } 7129 else { 7130 PetscInt oldOff = 0; 7131 for (p = 0; p < numPoints; p++) { 7132 PetscInt cStart = newPointOffsets[0][p]; 7133 PetscInt b = points[2 * p]; 7134 PetscInt c, r, k; 7135 PetscInt dof; 7136 7137 PetscCall(PetscSectionGetDof(section,b,&dof)); 7138 if (!dof) { 7139 continue; 7140 } 7141 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7142 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7143 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7144 7145 for (r = 0; r < numIndices; r++) { 7146 for (c = 0; c < nCols; c++) { 7147 for (k = 0; k < dof; k++) { 7148 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7149 } 7150 } 7151 } 7152 } 7153 else { 7154 /* copy this column as is */ 7155 for (r = 0; r < numIndices; r++) { 7156 for (c = 0; c < dof; c++) { 7157 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7158 } 7159 } 7160 } 7161 oldOff += dof; 7162 } 7163 } 7164 7165 if (multiplyLeft) { 7166 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7167 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7168 /* multiply constraints transpose on the left */ 7169 if (numFields) { 7170 for (f = 0; f < numFields; f++) { 7171 PetscInt oldOff = offsets[f]; 7172 7173 for (p = 0; p < numPoints; p++) { 7174 PetscInt rStart = newPointOffsets[f][p]; 7175 PetscInt b = points[2 * p]; 7176 PetscInt c, r, k; 7177 PetscInt dof; 7178 7179 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7180 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7181 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7182 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7183 7184 for (r = 0; r < nRows; r++) { 7185 for (c = 0; c < newNumIndices; c++) { 7186 for (k = 0; k < dof; k++) { 7187 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7188 } 7189 } 7190 } 7191 } 7192 else { 7193 /* copy this row as is */ 7194 for (r = 0; r < dof; r++) { 7195 for (c = 0; c < newNumIndices; c++) { 7196 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7197 } 7198 } 7199 } 7200 oldOff += dof; 7201 } 7202 } 7203 } 7204 else { 7205 PetscInt oldOff = 0; 7206 7207 for (p = 0; p < numPoints; p++) { 7208 PetscInt rStart = newPointOffsets[0][p]; 7209 PetscInt b = points[2 * p]; 7210 PetscInt c, r, k; 7211 PetscInt dof; 7212 7213 PetscCall(PetscSectionGetDof(section,b,&dof)); 7214 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7215 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7216 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7217 7218 for (r = 0; r < nRows; r++) { 7219 for (c = 0; c < newNumIndices; c++) { 7220 for (k = 0; k < dof; k++) { 7221 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7222 } 7223 } 7224 } 7225 } 7226 else { 7227 /* copy this row as is */ 7228 for (r = 0; r < dof; r++) { 7229 for (c = 0; c < newNumIndices; c++) { 7230 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7231 } 7232 } 7233 } 7234 oldOff += dof; 7235 } 7236 } 7237 7238 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7239 } 7240 else { 7241 newValues = tmpValues; 7242 } 7243 } 7244 7245 /* clean up */ 7246 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7247 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7248 7249 if (numFields) { 7250 for (f = 0; f < numFields; f++) { 7251 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7252 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7253 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7254 } 7255 } 7256 else { 7257 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7258 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7259 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7260 } 7261 PetscCall(ISRestoreIndices(aIS,&anchors)); 7262 7263 /* output */ 7264 if (outPoints) { 7265 *outPoints = newPoints; 7266 } 7267 else { 7268 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7269 } 7270 if (outValues) { 7271 *outValues = newValues; 7272 } 7273 for (f = 0; f <= numFields; f++) { 7274 offsets[f] = newOffsets[f]; 7275 } 7276 PetscFunctionReturn(0); 7277 } 7278 7279 /*@C 7280 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7281 7282 Not collective 7283 7284 Input Parameters: 7285 + dm - The DM 7286 . section - The PetscSection describing the points (a local section) 7287 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7288 . point - The point defining the closure 7289 - useClPerm - Use the closure point permutation if available 7290 7291 Output Parameters: 7292 + numIndices - The number of dof indices in the closure of point with the input sections 7293 . indices - The dof indices 7294 . outOffsets - Array to write the field offsets into, or NULL 7295 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7296 7297 Notes: 7298 Must call DMPlexRestoreClosureIndices() to free allocated memory 7299 7300 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7301 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7302 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7303 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7304 indices (with the above semantics) are implied. 7305 7306 Level: advanced 7307 7308 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7309 @*/ 7310 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7311 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7312 { 7313 /* Closure ordering */ 7314 PetscSection clSection; 7315 IS clPoints; 7316 const PetscInt *clp; 7317 PetscInt *points; 7318 const PetscInt *clperm = NULL; 7319 /* Dof permutation and sign flips */ 7320 const PetscInt **perms[32] = {NULL}; 7321 const PetscScalar **flips[32] = {NULL}; 7322 PetscScalar *valCopy = NULL; 7323 /* Hanging node constraints */ 7324 PetscInt *pointsC = NULL; 7325 PetscScalar *valuesC = NULL; 7326 PetscInt NclC, NiC; 7327 7328 PetscInt *idx; 7329 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7330 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7331 7332 PetscFunctionBeginHot; 7333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7334 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7335 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7336 if (numIndices) PetscValidIntPointer(numIndices, 6); 7337 if (indices) PetscValidPointer(indices, 7); 7338 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7339 if (values) PetscValidPointer(values, 9); 7340 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7341 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7342 PetscCall(PetscArrayzero(offsets, 32)); 7343 /* 1) Get points in closure */ 7344 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7345 if (useClPerm) { 7346 PetscInt depth, clsize; 7347 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7348 for (clsize=0,p=0; p<Ncl; p++) { 7349 PetscInt dof; 7350 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7351 clsize += dof; 7352 } 7353 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7354 } 7355 /* 2) Get number of indices on these points and field offsets from section */ 7356 for (p = 0; p < Ncl*2; p += 2) { 7357 PetscInt dof, fdof; 7358 7359 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7360 for (f = 0; f < Nf; ++f) { 7361 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7362 offsets[f+1] += fdof; 7363 } 7364 Ni += dof; 7365 } 7366 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7367 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7368 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7369 for (f = 0; f < PetscMax(1, Nf); ++f) { 7370 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7371 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7372 /* may need to apply sign changes to the element matrix */ 7373 if (values && flips[f]) { 7374 PetscInt foffset = offsets[f]; 7375 7376 for (p = 0; p < Ncl; ++p) { 7377 PetscInt pnt = points[2*p], fdof; 7378 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7379 7380 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7381 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7382 if (flip) { 7383 PetscInt i, j, k; 7384 7385 if (!valCopy) { 7386 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7387 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7388 *values = valCopy; 7389 } 7390 for (i = 0; i < fdof; ++i) { 7391 PetscScalar fval = flip[i]; 7392 7393 for (k = 0; k < Ni; ++k) { 7394 valCopy[Ni * (foffset + i) + k] *= fval; 7395 valCopy[Ni * k + (foffset + i)] *= fval; 7396 } 7397 } 7398 } 7399 foffset += fdof; 7400 } 7401 } 7402 } 7403 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7404 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7405 if (NclC) { 7406 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7407 for (f = 0; f < PetscMax(1, Nf); ++f) { 7408 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7409 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7410 } 7411 for (f = 0; f < PetscMax(1, Nf); ++f) { 7412 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7413 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7414 } 7415 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7416 Ncl = NclC; 7417 Ni = NiC; 7418 points = pointsC; 7419 if (values) *values = valuesC; 7420 } 7421 /* 5) Calculate indices */ 7422 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7423 if (Nf) { 7424 PetscInt idxOff; 7425 PetscBool useFieldOffsets; 7426 7427 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7428 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7429 if (useFieldOffsets) { 7430 for (p = 0; p < Ncl; ++p) { 7431 const PetscInt pnt = points[p*2]; 7432 7433 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7434 } 7435 } else { 7436 for (p = 0; p < Ncl; ++p) { 7437 const PetscInt pnt = points[p*2]; 7438 7439 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7440 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7441 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7442 * global section. */ 7443 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7444 } 7445 } 7446 } else { 7447 PetscInt off = 0, idxOff; 7448 7449 for (p = 0; p < Ncl; ++p) { 7450 const PetscInt pnt = points[p*2]; 7451 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7452 7453 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7454 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7455 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7456 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7457 } 7458 } 7459 /* 6) Cleanup */ 7460 for (f = 0; f < PetscMax(1, Nf); ++f) { 7461 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7462 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7463 } 7464 if (NclC) { 7465 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7466 } else { 7467 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7468 } 7469 7470 if (numIndices) *numIndices = Ni; 7471 if (indices) *indices = idx; 7472 PetscFunctionReturn(0); 7473 } 7474 7475 /*@C 7476 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7477 7478 Not collective 7479 7480 Input Parameters: 7481 + dm - The DM 7482 . section - The PetscSection describing the points (a local section) 7483 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7484 . point - The point defining the closure 7485 - useClPerm - Use the closure point permutation if available 7486 7487 Output Parameters: 7488 + numIndices - The number of dof indices in the closure of point with the input sections 7489 . indices - The dof indices 7490 . outOffsets - Array to write the field offsets into, or NULL 7491 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7492 7493 Notes: 7494 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7495 7496 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7497 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7498 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7499 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7500 indices (with the above semantics) are implied. 7501 7502 Level: advanced 7503 7504 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7505 @*/ 7506 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7507 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7508 { 7509 PetscFunctionBegin; 7510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7511 PetscValidPointer(indices, 7); 7512 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7513 PetscFunctionReturn(0); 7514 } 7515 7516 /*@C 7517 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7518 7519 Not collective 7520 7521 Input Parameters: 7522 + dm - The DM 7523 . section - The section describing the layout in v, or NULL to use the default section 7524 . globalSection - The section describing the layout in v, or NULL to use the default global section 7525 . A - The matrix 7526 . point - The point in the DM 7527 . values - The array of values 7528 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7529 7530 Fortran Notes: 7531 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7532 7533 Level: intermediate 7534 7535 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7536 @*/ 7537 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7538 { 7539 DM_Plex *mesh = (DM_Plex*) dm->data; 7540 PetscInt *indices; 7541 PetscInt numIndices; 7542 const PetscScalar *valuesOrig = values; 7543 PetscErrorCode ierr; 7544 7545 PetscFunctionBegin; 7546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7547 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7548 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7549 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7550 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7551 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7552 7553 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7554 7555 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7556 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7557 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7558 if (ierr) { 7559 PetscMPIInt rank; 7560 7561 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7562 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7563 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7564 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7565 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7566 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7567 } 7568 if (mesh->printFEM > 1) { 7569 PetscInt i; 7570 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7571 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7572 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7573 } 7574 7575 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7576 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7577 PetscFunctionReturn(0); 7578 } 7579 7580 /*@C 7581 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7582 7583 Not collective 7584 7585 Input Parameters: 7586 + dmRow - The DM for the row fields 7587 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7588 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7589 . dmCol - The DM for the column fields 7590 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7591 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7592 . A - The matrix 7593 . point - The point in the DMs 7594 . values - The array of values 7595 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7596 7597 Level: intermediate 7598 7599 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7600 @*/ 7601 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7602 { 7603 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7604 PetscInt *indicesRow, *indicesCol; 7605 PetscInt numIndicesRow, numIndicesCol; 7606 const PetscScalar *valuesOrig = values; 7607 PetscErrorCode ierr; 7608 7609 PetscFunctionBegin; 7610 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7611 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7612 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7613 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7614 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7615 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7616 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7617 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7618 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7619 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7620 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7621 7622 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7623 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7624 7625 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7626 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7627 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7628 if (ierr) { 7629 PetscMPIInt rank; 7630 7631 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7632 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7633 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7634 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7635 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7636 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7637 } 7638 7639 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7640 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7641 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7642 PetscFunctionReturn(0); 7643 } 7644 7645 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7646 { 7647 DM_Plex *mesh = (DM_Plex*) dmf->data; 7648 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7649 PetscInt *cpoints = NULL; 7650 PetscInt *findices, *cindices; 7651 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7652 PetscInt foffsets[32], coffsets[32]; 7653 DMPolytopeType ct; 7654 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7655 PetscErrorCode ierr; 7656 7657 PetscFunctionBegin; 7658 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7659 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7660 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7661 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7662 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7663 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7664 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7665 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7666 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7667 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7668 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7669 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7670 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7671 PetscCall(PetscArrayzero(foffsets, 32)); 7672 PetscCall(PetscArrayzero(coffsets, 32)); 7673 /* Column indices */ 7674 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7675 maxFPoints = numCPoints; 7676 /* Compress out points not in the section */ 7677 /* TODO: Squeeze out points with 0 dof as well */ 7678 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7679 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7680 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7681 cpoints[q*2] = cpoints[p]; 7682 cpoints[q*2+1] = cpoints[p+1]; 7683 ++q; 7684 } 7685 } 7686 numCPoints = q; 7687 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7688 PetscInt fdof; 7689 7690 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7691 if (!dof) continue; 7692 for (f = 0; f < numFields; ++f) { 7693 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7694 coffsets[f+1] += fdof; 7695 } 7696 numCIndices += dof; 7697 } 7698 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7699 /* Row indices */ 7700 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7701 { 7702 DMPlexTransform tr; 7703 DMPolytopeType *rct; 7704 PetscInt *rsize, *rcone, *rornt, Nt; 7705 7706 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7707 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7708 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7709 numSubcells = rsize[Nt-1]; 7710 PetscCall(DMPlexTransformDestroy(&tr)); 7711 } 7712 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7713 for (r = 0, q = 0; r < numSubcells; ++r) { 7714 /* TODO Map from coarse to fine cells */ 7715 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7716 /* Compress out points not in the section */ 7717 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7718 for (p = 0; p < numFPoints*2; p += 2) { 7719 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7720 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7721 if (!dof) continue; 7722 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7723 if (s < q) continue; 7724 ftotpoints[q*2] = fpoints[p]; 7725 ftotpoints[q*2+1] = fpoints[p+1]; 7726 ++q; 7727 } 7728 } 7729 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7730 } 7731 numFPoints = q; 7732 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7733 PetscInt fdof; 7734 7735 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7736 if (!dof) continue; 7737 for (f = 0; f < numFields; ++f) { 7738 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7739 foffsets[f+1] += fdof; 7740 } 7741 numFIndices += dof; 7742 } 7743 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7744 7745 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7746 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7747 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7748 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7749 if (numFields) { 7750 const PetscInt **permsF[32] = {NULL}; 7751 const PetscInt **permsC[32] = {NULL}; 7752 7753 for (f = 0; f < numFields; f++) { 7754 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7755 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7756 } 7757 for (p = 0; p < numFPoints; p++) { 7758 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7759 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7760 } 7761 for (p = 0; p < numCPoints; p++) { 7762 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7763 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7764 } 7765 for (f = 0; f < numFields; f++) { 7766 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7767 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7768 } 7769 } else { 7770 const PetscInt **permsF = NULL; 7771 const PetscInt **permsC = NULL; 7772 7773 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7774 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7775 for (p = 0, off = 0; p < numFPoints; p++) { 7776 const PetscInt *perm = permsF ? permsF[p] : NULL; 7777 7778 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7779 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7780 } 7781 for (p = 0, off = 0; p < numCPoints; p++) { 7782 const PetscInt *perm = permsC ? permsC[p] : NULL; 7783 7784 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7785 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7786 } 7787 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7788 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7789 } 7790 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7791 /* TODO: flips */ 7792 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7793 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7794 if (ierr) { 7795 PetscMPIInt rank; 7796 7797 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7798 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7799 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7800 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7801 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7802 } 7803 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7804 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7805 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7806 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7807 PetscFunctionReturn(0); 7808 } 7809 7810 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7811 { 7812 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7813 PetscInt *cpoints = NULL; 7814 PetscInt foffsets[32], coffsets[32]; 7815 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7816 DMPolytopeType ct; 7817 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7818 7819 PetscFunctionBegin; 7820 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7821 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7822 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7823 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7824 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7825 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7826 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7827 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7828 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7829 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7830 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7831 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7832 PetscCall(PetscArrayzero(foffsets, 32)); 7833 PetscCall(PetscArrayzero(coffsets, 32)); 7834 /* Column indices */ 7835 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7836 maxFPoints = numCPoints; 7837 /* Compress out points not in the section */ 7838 /* TODO: Squeeze out points with 0 dof as well */ 7839 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7840 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7841 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7842 cpoints[q*2] = cpoints[p]; 7843 cpoints[q*2+1] = cpoints[p+1]; 7844 ++q; 7845 } 7846 } 7847 numCPoints = q; 7848 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7849 PetscInt fdof; 7850 7851 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7852 if (!dof) continue; 7853 for (f = 0; f < numFields; ++f) { 7854 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7855 coffsets[f+1] += fdof; 7856 } 7857 numCIndices += dof; 7858 } 7859 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7860 /* Row indices */ 7861 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7862 { 7863 DMPlexTransform tr; 7864 DMPolytopeType *rct; 7865 PetscInt *rsize, *rcone, *rornt, Nt; 7866 7867 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7868 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7869 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7870 numSubcells = rsize[Nt-1]; 7871 PetscCall(DMPlexTransformDestroy(&tr)); 7872 } 7873 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7874 for (r = 0, q = 0; r < numSubcells; ++r) { 7875 /* TODO Map from coarse to fine cells */ 7876 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7877 /* Compress out points not in the section */ 7878 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7879 for (p = 0; p < numFPoints*2; p += 2) { 7880 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7881 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7882 if (!dof) continue; 7883 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7884 if (s < q) continue; 7885 ftotpoints[q*2] = fpoints[p]; 7886 ftotpoints[q*2+1] = fpoints[p+1]; 7887 ++q; 7888 } 7889 } 7890 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7891 } 7892 numFPoints = q; 7893 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7894 PetscInt fdof; 7895 7896 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7897 if (!dof) continue; 7898 for (f = 0; f < numFields; ++f) { 7899 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7900 foffsets[f+1] += fdof; 7901 } 7902 numFIndices += dof; 7903 } 7904 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7905 7906 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7907 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7908 if (numFields) { 7909 const PetscInt **permsF[32] = {NULL}; 7910 const PetscInt **permsC[32] = {NULL}; 7911 7912 for (f = 0; f < numFields; f++) { 7913 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7914 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7915 } 7916 for (p = 0; p < numFPoints; p++) { 7917 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7918 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7919 } 7920 for (p = 0; p < numCPoints; p++) { 7921 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7922 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7923 } 7924 for (f = 0; f < numFields; f++) { 7925 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7926 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7927 } 7928 } else { 7929 const PetscInt **permsF = NULL; 7930 const PetscInt **permsC = NULL; 7931 7932 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7933 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7934 for (p = 0, off = 0; p < numFPoints; p++) { 7935 const PetscInt *perm = permsF ? permsF[p] : NULL; 7936 7937 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7938 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7939 } 7940 for (p = 0, off = 0; p < numCPoints; p++) { 7941 const PetscInt *perm = permsC ? permsC[p] : NULL; 7942 7943 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7944 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7945 } 7946 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7947 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7948 } 7949 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7950 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7951 PetscFunctionReturn(0); 7952 } 7953 7954 /*@C 7955 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7956 7957 Input Parameter: 7958 . dm - The DMPlex object 7959 7960 Output Parameter: 7961 . cellHeight - The height of a cell 7962 7963 Level: developer 7964 7965 .seealso `DMPlexSetVTKCellHeight()` 7966 @*/ 7967 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7968 { 7969 DM_Plex *mesh = (DM_Plex*) dm->data; 7970 7971 PetscFunctionBegin; 7972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7973 PetscValidIntPointer(cellHeight, 2); 7974 *cellHeight = mesh->vtkCellHeight; 7975 PetscFunctionReturn(0); 7976 } 7977 7978 /*@C 7979 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7980 7981 Input Parameters: 7982 + dm - The DMPlex object 7983 - cellHeight - The height of a cell 7984 7985 Level: developer 7986 7987 .seealso `DMPlexGetVTKCellHeight()` 7988 @*/ 7989 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7990 { 7991 DM_Plex *mesh = (DM_Plex*) dm->data; 7992 7993 PetscFunctionBegin; 7994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7995 mesh->vtkCellHeight = cellHeight; 7996 PetscFunctionReturn(0); 7997 } 7998 7999 /*@ 8000 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8001 8002 Input Parameter: 8003 . dm - The DMPlex object 8004 8005 Output Parameters: 8006 + gcStart - The first ghost cell, or NULL 8007 - gcEnd - The upper bound on ghost cells, or NULL 8008 8009 Level: advanced 8010 8011 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8012 @*/ 8013 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8014 { 8015 DMLabel ctLabel; 8016 8017 PetscFunctionBegin; 8018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8019 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8020 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 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