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 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: `VecViewFromOptions()`, `VecView()` 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 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); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 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])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 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])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else PetscCall(VecLoad_Default(v, viewer)); 622 PetscFunctionReturn(0); 623 } 624 625 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool ishdf5,isexodusii; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 634 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 635 if (ishdf5) { 636 #if defined(PETSC_HAVE_HDF5) 637 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 638 #else 639 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 640 #endif 641 } else if (isexodusii) { 642 #if defined(PETSC_HAVE_EXODUSII) 643 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 644 #else 645 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 646 #endif 647 } else PetscCall(VecLoad_Default(v, viewer)); 648 PetscFunctionReturn(0); 649 } 650 651 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 652 { 653 DM dm; 654 PetscViewerFormat format; 655 PetscBool ishdf5; 656 657 PetscFunctionBegin; 658 PetscCall(VecGetDM(originalv, &dm)); 659 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 660 PetscCall(PetscViewerGetFormat(viewer, &format)); 661 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 662 if (format == PETSC_VIEWER_NATIVE) { 663 if (dm->useNatural) { 664 if (dm->sfNatural) { 665 if (ishdf5) { 666 #if defined(PETSC_HAVE_HDF5) 667 Vec v; 668 const char *vecname; 669 670 PetscCall(DMGetGlobalVector(dm, &v)); 671 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 672 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 673 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 674 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 675 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 676 PetscCall(DMRestoreGlobalVector(dm, &v)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 681 } 682 } else PetscCall(VecLoad_Default(originalv, viewer)); 683 } 684 PetscFunctionReturn(0); 685 } 686 687 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 688 { 689 PetscSection coordSection; 690 Vec coordinates; 691 DMLabel depthLabel, celltypeLabel; 692 const char *name[4]; 693 const PetscScalar *a; 694 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 695 696 PetscFunctionBegin; 697 PetscCall(DMGetDimension(dm, &dim)); 698 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 699 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 700 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 701 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 702 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 703 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 704 PetscCall(VecGetArrayRead(coordinates, &a)); 705 name[0] = "vertex"; 706 name[1] = "edge"; 707 name[dim-1] = "face"; 708 name[dim] = "cell"; 709 for (c = cStart; c < cEnd; ++c) { 710 PetscInt *closure = NULL; 711 PetscInt closureSize, cl, ct; 712 713 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 714 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 715 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 716 PetscCall(PetscViewerASCIIPushTab(viewer)); 717 for (cl = 0; cl < closureSize*2; cl += 2) { 718 PetscInt point = closure[cl], depth, dof, off, d, p; 719 720 if ((point < pStart) || (point >= pEnd)) continue; 721 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 722 if (!dof) continue; 723 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 724 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 725 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 726 for (p = 0; p < dof/dim; ++p) { 727 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 728 for (d = 0; d < dim; ++d) { 729 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 730 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 731 } 732 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 733 } 734 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 735 } 736 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 737 PetscCall(PetscViewerASCIIPopTab(viewer)); 738 } 739 PetscCall(VecRestoreArrayRead(coordinates, &a)); 740 PetscFunctionReturn(0); 741 } 742 743 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 744 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 745 746 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 747 { 748 PetscInt i; 749 750 PetscFunctionBegin; 751 if (dim > 3) { 752 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 753 } else { 754 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 755 756 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 757 switch (cs) { 758 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 759 case CS_POLAR: 760 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 761 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 762 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 763 break; 764 case CS_CYLINDRICAL: 765 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 766 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 767 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 768 trcoords[2] = coords[2]; 769 break; 770 case CS_SPHERICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 773 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 774 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 775 break; 776 } 777 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 778 } 779 PetscFunctionReturn(0); 780 } 781 782 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 783 { 784 DM_Plex *mesh = (DM_Plex*) dm->data; 785 DM cdm, cdmCell; 786 PetscSection coordSection, coordSectionCell; 787 Vec coordinates, coordinatesCell; 788 PetscViewerFormat format; 789 790 PetscFunctionBegin; 791 PetscCall(DMGetCoordinateDM(dm, &cdm)); 792 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 793 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 794 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 795 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 796 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 797 PetscCall(PetscViewerGetFormat(viewer, &format)); 798 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 799 const char *name; 800 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 801 PetscInt pStart, pEnd, p, numLabels, l; 802 PetscMPIInt rank, size; 803 804 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 805 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 806 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 807 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 808 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 809 PetscCall(DMGetDimension(dm, &dim)); 810 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 811 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 812 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 813 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 814 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 815 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 816 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 817 for (p = pStart; p < pEnd; ++p) { 818 PetscInt dof, off, s; 819 820 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 821 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 822 for (s = off; s < off+dof; ++s) { 823 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 824 } 825 } 826 PetscCall(PetscViewerFlush(viewer)); 827 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 828 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 829 for (p = pStart; p < pEnd; ++p) { 830 PetscInt dof, off, c; 831 832 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 833 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 834 for (c = off; c < off+dof; ++c) { 835 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 836 } 837 } 838 PetscCall(PetscViewerFlush(viewer)); 839 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 840 if (coordSection && coordinates) { 841 CoordSystem cs = CS_CARTESIAN; 842 const PetscScalar *array, *arrayCell = NULL; 843 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 844 PetscMPIInt rank; 845 const char *name; 846 847 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 848 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 849 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 850 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 851 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 852 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 853 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 854 pStart = PetscMin(pvStart, pcStart); 855 pEnd = PetscMax(pvEnd, pcEnd); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 863 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 864 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 865 for (p = pStart; p < pEnd; ++p) { 866 PetscInt dof, off; 867 868 if (p >= pvStart && p < pvEnd) { 869 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 870 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 871 if (dof) { 872 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 873 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 874 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 875 } 876 } 877 if (cdmCell && p >= pcStart && p < pcEnd) { 878 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 879 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 880 if (dof) { 881 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 882 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 883 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 884 } 885 } 886 } 887 PetscCall(PetscViewerFlush(viewer)); 888 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 889 PetscCall(VecRestoreArrayRead(coordinates, &array)); 890 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 891 } 892 PetscCall(DMGetNumLabels(dm, &numLabels)); 893 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 894 for (l = 0; l < numLabels; ++l) { 895 DMLabel label; 896 PetscBool isdepth; 897 const char *name; 898 899 PetscCall(DMGetLabelName(dm, l, &name)); 900 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 901 if (isdepth) continue; 902 PetscCall(DMGetLabel(dm, name, &label)); 903 PetscCall(DMLabelView(label, viewer)); 904 } 905 if (size > 1) { 906 PetscSF sf; 907 908 PetscCall(DMGetPointSF(dm, &sf)); 909 PetscCall(PetscSFView(sf, viewer)); 910 } 911 PetscCall(PetscViewerFlush(viewer)); 912 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 913 const char *name, *color; 914 const char *defcolors[3] = {"gray", "orange", "green"}; 915 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 916 char lname[PETSC_MAX_PATH_LEN]; 917 PetscReal scale = 2.0; 918 PetscReal tikzscale = 1.0; 919 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 920 double tcoords[3]; 921 PetscScalar *coords; 922 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 923 PetscMPIInt rank, size; 924 char **names, **colors, **lcolors; 925 PetscBool flg, lflg; 926 PetscBT wp = NULL; 927 PetscInt pEnd, pStart; 928 929 PetscCall(DMGetDimension(dm, &dim)); 930 PetscCall(DMPlexGetDepth(dm, &depth)); 931 PetscCall(DMGetNumLabels(dm, &numLabels)); 932 numLabels = PetscMax(numLabels, 10); 933 numColors = 10; 934 numLColors = 10; 935 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 936 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 937 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 938 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 939 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 940 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 941 n = 4; 942 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 943 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 944 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 945 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 946 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 947 if (!useLabels) numLabels = 0; 948 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 949 if (!useColors) { 950 numColors = 3; 951 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 952 } 953 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 954 if (!useColors) { 955 numLColors = 4; 956 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 957 } 958 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 959 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 960 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 961 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 962 if (depth < dim) plotEdges = PETSC_FALSE; 963 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 964 965 /* filter points with labelvalue != labeldefaultvalue */ 966 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 967 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 968 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 970 if (lflg) { 971 DMLabel lbl; 972 973 PetscCall(DMGetLabel(dm, lname, &lbl)); 974 if (lbl) { 975 PetscInt val, defval; 976 977 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 978 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 979 for (c = pStart; c < pEnd; c++) { 980 PetscInt *closure = NULL; 981 PetscInt closureSize; 982 983 PetscCall(DMLabelGetValue(lbl, c, &val)); 984 if (val == defval) continue; 985 986 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 987 for (p = 0; p < closureSize*2; p += 2) { 988 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 989 } 990 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 } 992 } 993 } 994 995 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 996 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 997 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 998 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 999 \\documentclass[tikz]{standalone}\n\n\ 1000 \\usepackage{pgflibraryshapes}\n\ 1001 \\usetikzlibrary{backgrounds}\n\ 1002 \\usetikzlibrary{arrows}\n\ 1003 \\begin{document}\n")); 1004 if (size > 1) { 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1006 for (p = 0; p < size; ++p) { 1007 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 1009 } 1010 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1011 } 1012 if (drawHasse) { 1013 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 1014 1015 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1016 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1027 } 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1029 1030 /* Plot vertices */ 1031 PetscCall(VecGetArray(coordinates, &coords)); 1032 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1033 for (v = vStart; v < vEnd; ++v) { 1034 PetscInt off, dof, d; 1035 PetscBool isLabeled = PETSC_FALSE; 1036 1037 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1038 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1039 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1040 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1041 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1042 for (d = 0; d < dof; ++d) { 1043 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1044 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1045 } 1046 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1047 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1048 for (d = 0; d < dof; ++d) { 1049 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1050 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1051 } 1052 if (drawHasse) color = colors[0%numColors]; 1053 else color = colors[rank%numColors]; 1054 for (l = 0; l < numLabels; ++l) { 1055 PetscInt val; 1056 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1057 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1058 } 1059 if (drawNumbers[0]) { 1060 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1061 } else if (drawColors[0]) { 1062 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1063 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1064 } 1065 PetscCall(VecRestoreArray(coordinates, &coords)); 1066 PetscCall(PetscViewerFlush(viewer)); 1067 /* Plot edges */ 1068 if (plotEdges) { 1069 PetscCall(VecGetArray(coordinates, &coords)); 1070 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1071 for (e = eStart; e < eEnd; ++e) { 1072 const PetscInt *cone; 1073 PetscInt coneSize, offA, offB, dof, d; 1074 1075 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1076 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1077 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1078 PetscCall(DMPlexGetCone(dm, e, &cone)); 1079 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1080 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1081 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1082 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1083 for (d = 0; d < dof; ++d) { 1084 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1085 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1086 } 1087 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1088 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1089 for (d = 0; d < dof; ++d) { 1090 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1091 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1092 } 1093 if (drawHasse) color = colors[1%numColors]; 1094 else color = colors[rank%numColors]; 1095 for (l = 0; l < numLabels; ++l) { 1096 PetscInt val; 1097 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1098 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1099 } 1100 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1101 } 1102 PetscCall(VecRestoreArray(coordinates, &coords)); 1103 PetscCall(PetscViewerFlush(viewer)); 1104 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1105 } 1106 /* Plot cells */ 1107 if (dim == 3 || !drawNumbers[1]) { 1108 for (e = eStart; e < eEnd; ++e) { 1109 const PetscInt *cone; 1110 1111 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1112 color = colors[rank%numColors]; 1113 for (l = 0; l < numLabels; ++l) { 1114 PetscInt val; 1115 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1116 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1117 } 1118 PetscCall(DMPlexGetCone(dm, e, &cone)); 1119 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1120 } 1121 } else { 1122 DMPolytopeType ct; 1123 1124 /* Drawing a 2D polygon */ 1125 for (c = cStart; c < cEnd; ++c) { 1126 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1127 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1128 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1129 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1130 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1131 const PetscInt *cone; 1132 PetscInt coneSize, e; 1133 1134 PetscCall(DMPlexGetCone(dm, c, &cone)); 1135 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1136 for (e = 0; e < coneSize; ++e) { 1137 const PetscInt *econe; 1138 1139 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1140 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)); 1141 } 1142 } else { 1143 PetscInt *closure = NULL; 1144 PetscInt closureSize, Nv = 0, v; 1145 1146 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1147 for (p = 0; p < closureSize*2; p += 2) { 1148 const PetscInt point = closure[p]; 1149 1150 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1151 } 1152 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1153 for (v = 0; v <= Nv; ++v) { 1154 const PetscInt vertex = closure[v%Nv]; 1155 1156 if (v > 0) { 1157 if (plotEdges) { 1158 const PetscInt *edge; 1159 PetscInt endpoints[2], ne; 1160 1161 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1162 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1163 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1164 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1165 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1166 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1167 } 1168 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1171 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1172 } 1173 } 1174 } 1175 PetscCall(VecGetArray(coordinates, &coords)); 1176 for (c = cStart; c < cEnd; ++c) { 1177 double ccoords[3] = {0.0, 0.0, 0.0}; 1178 PetscBool isLabeled = PETSC_FALSE; 1179 PetscInt *closure = NULL; 1180 PetscInt closureSize, dof, d, n = 0; 1181 1182 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1183 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1184 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1185 for (p = 0; p < closureSize*2; p += 2) { 1186 const PetscInt point = closure[p]; 1187 PetscInt off; 1188 1189 if ((point < vStart) || (point >= vEnd)) continue; 1190 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1191 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1192 for (d = 0; d < dof; ++d) { 1193 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1194 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1195 } 1196 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1197 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1198 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1199 ++n; 1200 } 1201 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1202 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1203 for (d = 0; d < dof; ++d) { 1204 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1205 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1206 } 1207 if (drawHasse) color = colors[depth%numColors]; 1208 else color = colors[rank%numColors]; 1209 for (l = 0; l < numLabels; ++l) { 1210 PetscInt val; 1211 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1212 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1213 } 1214 if (drawNumbers[dim]) { 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1216 } else if (drawColors[dim]) { 1217 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1219 } 1220 PetscCall(VecRestoreArray(coordinates, &coords)); 1221 if (drawHasse) { 1222 color = colors[depth%numColors]; 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1226 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1227 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1228 1229 color = colors[1%numColors]; 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1235 1236 color = colors[0%numColors]; 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1242 1243 for (p = pStart; p < pEnd; ++p) { 1244 const PetscInt *cone; 1245 PetscInt coneSize, cp; 1246 1247 PetscCall(DMPlexGetCone(dm, p, &cone)); 1248 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1249 for (cp = 0; cp < coneSize; ++cp) { 1250 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1251 } 1252 } 1253 } 1254 PetscCall(PetscViewerFlush(viewer)); 1255 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1257 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1258 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1259 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1260 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1261 PetscCall(PetscFree3(names, colors, lcolors)); 1262 PetscCall(PetscBTDestroy(&wp)); 1263 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1264 Vec cown,acown; 1265 VecScatter sct; 1266 ISLocalToGlobalMapping g2l; 1267 IS gid,acis; 1268 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1269 MPI_Group ggroup,ngroup; 1270 PetscScalar *array,nid; 1271 const PetscInt *idxs; 1272 PetscInt *idxs2,*start,*adjacency,*work; 1273 PetscInt64 lm[3],gm[3]; 1274 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1275 PetscMPIInt d1,d2,rank; 1276 1277 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1278 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1279 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1280 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1281 #endif 1282 if (ncomm != MPI_COMM_NULL) { 1283 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1284 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1285 d1 = 0; 1286 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1287 nid = d2; 1288 PetscCallMPI(MPI_Group_free(&ggroup)); 1289 PetscCallMPI(MPI_Group_free(&ngroup)); 1290 PetscCallMPI(MPI_Comm_free(&ncomm)); 1291 } else nid = 0.0; 1292 1293 /* Get connectivity */ 1294 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1295 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1296 1297 /* filter overlapped local cells */ 1298 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1299 PetscCall(ISGetIndices(gid,&idxs)); 1300 PetscCall(ISGetLocalSize(gid,&cum)); 1301 PetscCall(PetscMalloc1(cum,&idxs2)); 1302 for (c = cStart, cum = 0; c < cEnd; c++) { 1303 if (idxs[c-cStart] < 0) continue; 1304 idxs2[cum++] = idxs[c-cStart]; 1305 } 1306 PetscCall(ISRestoreIndices(gid,&idxs)); 1307 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1308 PetscCall(ISDestroy(&gid)); 1309 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1310 1311 /* support for node-aware cell locality */ 1312 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1313 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1314 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1315 PetscCall(VecGetArray(cown,&array)); 1316 for (c = 0; c < numVertices; c++) array[c] = nid; 1317 PetscCall(VecRestoreArray(cown,&array)); 1318 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1319 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1320 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1321 PetscCall(ISDestroy(&acis)); 1322 PetscCall(VecScatterDestroy(&sct)); 1323 PetscCall(VecDestroy(&cown)); 1324 1325 /* compute edgeCut */ 1326 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1327 PetscCall(PetscMalloc1(cum,&work)); 1328 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1329 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1330 PetscCall(ISDestroy(&gid)); 1331 PetscCall(VecGetArray(acown,&array)); 1332 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1333 PetscInt totl; 1334 1335 totl = start[c+1]-start[c]; 1336 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1337 for (i = 0; i < totl; i++) { 1338 if (work[i] < 0) { 1339 ect += 1; 1340 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1341 } 1342 } 1343 } 1344 PetscCall(PetscFree(work)); 1345 PetscCall(VecRestoreArray(acown,&array)); 1346 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1347 lm[1] = -numVertices; 1348 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1350 lm[0] = ect; /* edgeCut */ 1351 lm[1] = ectn; /* node-aware edgeCut */ 1352 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1353 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1354 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1355 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1356 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1357 #else 1358 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1359 #endif 1360 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1361 PetscCall(PetscFree(start)); 1362 PetscCall(PetscFree(adjacency)); 1363 PetscCall(VecDestroy(&acown)); 1364 } else { 1365 const char *name; 1366 PetscInt *sizes, *hybsizes, *ghostsizes; 1367 PetscInt locDepth, depth, cellHeight, dim, d; 1368 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1369 PetscInt numLabels, l, maxSize = 17; 1370 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1371 MPI_Comm comm; 1372 PetscMPIInt size, rank; 1373 1374 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1375 PetscCallMPI(MPI_Comm_size(comm, &size)); 1376 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1377 PetscCall(DMGetDimension(dm, &dim)); 1378 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1379 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1380 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1381 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1382 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1383 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1384 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1385 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1386 gcNum = gcEnd - gcStart; 1387 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1388 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1389 for (d = 0; d <= depth; d++) { 1390 PetscInt Nc[2] = {0, 0}, ict; 1391 1392 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1393 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1394 ict = ct0; 1395 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1396 ct0 = (DMPolytopeType) ict; 1397 for (p = pStart; p < pEnd; ++p) { 1398 DMPolytopeType ct; 1399 1400 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1401 if (ct == ct0) ++Nc[0]; 1402 else ++Nc[1]; 1403 } 1404 if (size < maxSize) { 1405 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1406 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1407 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1408 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1409 for (p = 0; p < size; ++p) { 1410 if (rank == 0) { 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1412 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1413 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1414 } 1415 } 1416 } else { 1417 PetscInt locMinMax[2]; 1418 1419 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1420 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1421 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1422 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1423 if (d == depth) { 1424 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1425 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1426 } 1427 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1429 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1430 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1431 } 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1433 } 1434 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1435 { 1436 const PetscReal *maxCell; 1437 const PetscReal *L; 1438 PetscBool localized; 1439 1440 PetscCall(DMGetPeriodicity(dm, &maxCell, &L)); 1441 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1442 if (L || localized) { 1443 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1444 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1445 if (L) { 1446 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1447 for (d = 0; d < dim; ++d) { 1448 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1449 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1450 } 1451 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1452 } 1453 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1454 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1455 } 1456 } 1457 PetscCall(DMGetNumLabels(dm, &numLabels)); 1458 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1459 for (l = 0; l < numLabels; ++l) { 1460 DMLabel label; 1461 const char *name; 1462 IS valueIS; 1463 const PetscInt *values; 1464 PetscInt numValues, v; 1465 1466 PetscCall(DMGetLabelName(dm, l, &name)); 1467 PetscCall(DMGetLabel(dm, name, &label)); 1468 PetscCall(DMLabelGetNumValues(label, &numValues)); 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1470 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1471 PetscCall(ISGetIndices(valueIS, &values)); 1472 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1473 for (v = 0; v < numValues; ++v) { 1474 PetscInt size; 1475 1476 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1477 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1478 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1479 } 1480 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1481 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1482 PetscCall(ISRestoreIndices(valueIS, &values)); 1483 PetscCall(ISDestroy(&valueIS)); 1484 } 1485 { 1486 char **labelNames; 1487 PetscInt Nl = numLabels; 1488 PetscBool flg; 1489 1490 PetscCall(PetscMalloc1(Nl, &labelNames)); 1491 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1492 for (l = 0; l < Nl; ++l) { 1493 DMLabel label; 1494 1495 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1496 if (flg) { 1497 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1498 PetscCall(DMLabelView(label, viewer)); 1499 } 1500 PetscCall(PetscFree(labelNames[l])); 1501 } 1502 PetscCall(PetscFree(labelNames)); 1503 } 1504 /* If no fields are specified, people do not want to see adjacency */ 1505 if (dm->Nf) { 1506 PetscInt f; 1507 1508 for (f = 0; f < dm->Nf; ++f) { 1509 const char *name; 1510 1511 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1512 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1513 PetscCall(PetscViewerASCIIPushTab(viewer)); 1514 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1515 if (dm->fields[f].adjacency[0]) { 1516 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1517 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1518 } else { 1519 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1520 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1521 } 1522 PetscCall(PetscViewerASCIIPopTab(viewer)); 1523 } 1524 } 1525 PetscCall(DMGetCoarseDM(dm, &cdm)); 1526 if (cdm) { 1527 PetscCall(PetscViewerASCIIPushTab(viewer)); 1528 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1529 PetscCall(PetscViewerASCIIPopTab(viewer)); 1530 } 1531 } 1532 PetscFunctionReturn(0); 1533 } 1534 1535 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1536 { 1537 DMPolytopeType ct; 1538 PetscMPIInt rank; 1539 PetscInt cdim; 1540 1541 PetscFunctionBegin; 1542 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1543 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1544 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1545 switch (ct) { 1546 case DM_POLYTOPE_SEGMENT: 1547 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1548 switch (cdim) { 1549 case 1: 1550 { 1551 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1552 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1553 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1556 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1557 } 1558 break; 1559 case 2: 1560 { 1561 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1562 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1563 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1564 1565 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1566 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)); 1567 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)); 1568 } 1569 break; 1570 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1571 } 1572 break; 1573 case DM_POLYTOPE_TRIANGLE: 1574 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1575 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1578 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1581 break; 1582 case DM_POLYTOPE_QUADRILATERAL: 1583 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1584 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1585 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1586 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1587 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1588 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1589 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1590 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1591 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1592 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1595 break; 1596 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1597 } 1598 PetscFunctionReturn(0); 1599 } 1600 1601 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1602 { 1603 DMPolytopeType ct; 1604 PetscReal centroid[2] = {0., 0.}; 1605 PetscMPIInt rank; 1606 PetscInt fillColor, v, e, d; 1607 1608 PetscFunctionBegin; 1609 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1610 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1611 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1612 switch (ct) { 1613 case DM_POLYTOPE_TRIANGLE: 1614 { 1615 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1616 1617 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1618 for (e = 0; e < 3; ++e) { 1619 refCoords[0] = refVertices[e*2+0]; 1620 refCoords[1] = refVertices[e*2+1]; 1621 for (d = 1; d <= edgeDiv; ++d) { 1622 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1623 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1624 } 1625 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1626 for (d = 0; d < edgeDiv; ++d) { 1627 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)); 1628 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1629 } 1630 } 1631 } 1632 break; 1633 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1634 } 1635 PetscFunctionReturn(0); 1636 } 1637 1638 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1639 { 1640 PetscDraw draw; 1641 DM cdm; 1642 PetscSection coordSection; 1643 Vec coordinates; 1644 const PetscScalar *coords; 1645 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1646 PetscReal *refCoords, *edgeCoords; 1647 PetscBool isnull, drawAffine = PETSC_TRUE; 1648 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1649 1650 PetscFunctionBegin; 1651 PetscCall(DMGetCoordinateDim(dm, &dim)); 1652 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1653 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1654 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1655 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1656 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1657 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1658 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1659 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1660 1661 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1662 PetscCall(PetscDrawIsNull(draw, &isnull)); 1663 if (isnull) PetscFunctionReturn(0); 1664 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1665 1666 PetscCall(VecGetLocalSize(coordinates, &N)); 1667 PetscCall(VecGetArrayRead(coordinates, &coords)); 1668 for (c = 0; c < N; c += dim) { 1669 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1670 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1671 } 1672 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1673 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1674 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1675 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1676 PetscCall(PetscDrawClear(draw)); 1677 1678 for (c = cStart; c < cEnd; ++c) { 1679 PetscScalar *coords = NULL; 1680 PetscInt numCoords; 1681 1682 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1683 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1684 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1685 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1686 } 1687 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1688 PetscCall(PetscDrawFlush(draw)); 1689 PetscCall(PetscDrawPause(draw)); 1690 PetscCall(PetscDrawSave(draw)); 1691 PetscFunctionReturn(0); 1692 } 1693 1694 #if defined(PETSC_HAVE_EXODUSII) 1695 #include <exodusII.h> 1696 #include <petscviewerexodusii.h> 1697 #endif 1698 1699 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1700 { 1701 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1702 char name[PETSC_MAX_PATH_LEN]; 1703 1704 PetscFunctionBegin; 1705 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1706 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1707 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1708 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1709 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1710 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1711 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1712 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1713 if (iascii) { 1714 PetscViewerFormat format; 1715 PetscCall(PetscViewerGetFormat(viewer, &format)); 1716 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1717 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1718 } else if (ishdf5) { 1719 #if defined(PETSC_HAVE_HDF5) 1720 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1721 #else 1722 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1723 #endif 1724 } else if (isvtk) { 1725 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1726 } else if (isdraw) { 1727 PetscCall(DMPlexView_Draw(dm, viewer)); 1728 } else if (isglvis) { 1729 PetscCall(DMPlexView_GLVis(dm, viewer)); 1730 #if defined(PETSC_HAVE_EXODUSII) 1731 } else if (isexodus) { 1732 /* 1733 exodusII requires that all sets be part of exactly one cell set. 1734 If the dm does not have a "Cell Sets" label defined, we create one 1735 with ID 1, containig all cells. 1736 Note that if the Cell Sets label is defined but does not cover all cells, 1737 we may still have a problem. This should probably be checked here or in the viewer; 1738 */ 1739 PetscInt numCS; 1740 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1741 if (!numCS) { 1742 PetscInt cStart, cEnd, c; 1743 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1744 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1745 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1746 } 1747 PetscCall(DMView_PlexExodusII(dm, viewer)); 1748 #endif 1749 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1750 1751 /* Optionally view the partition */ 1752 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1753 if (flg) { 1754 Vec ranks; 1755 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1756 PetscCall(VecView(ranks, viewer)); 1757 PetscCall(VecDestroy(&ranks)); 1758 } 1759 /* Optionally view a label */ 1760 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1761 if (flg) { 1762 DMLabel label; 1763 Vec val; 1764 1765 PetscCall(DMGetLabel(dm, name, &label)); 1766 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1767 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1768 PetscCall(VecView(val, viewer)); 1769 PetscCall(VecDestroy(&val)); 1770 } 1771 PetscFunctionReturn(0); 1772 } 1773 1774 /*@ 1775 DMPlexTopologyView - Saves a DMPlex topology into a file 1776 1777 Collective on DM 1778 1779 Input Parameters: 1780 + dm - The DM whose topology is to be saved 1781 - viewer - The PetscViewer for saving 1782 1783 Level: advanced 1784 1785 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1786 @*/ 1787 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1788 { 1789 PetscBool ishdf5; 1790 1791 PetscFunctionBegin; 1792 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1793 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1794 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1795 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1796 if (ishdf5) { 1797 #if defined(PETSC_HAVE_HDF5) 1798 PetscViewerFormat format; 1799 PetscCall(PetscViewerGetFormat(viewer, &format)); 1800 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1801 IS globalPointNumbering; 1802 1803 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1804 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1805 PetscCall(ISDestroy(&globalPointNumbering)); 1806 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1807 #else 1808 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1809 #endif 1810 } 1811 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1812 PetscFunctionReturn(0); 1813 } 1814 1815 /*@ 1816 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1817 1818 Collective on DM 1819 1820 Input Parameters: 1821 + dm - The DM whose coordinates are to be saved 1822 - viewer - The PetscViewer for saving 1823 1824 Level: advanced 1825 1826 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1827 @*/ 1828 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1829 { 1830 PetscBool ishdf5; 1831 1832 PetscFunctionBegin; 1833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1834 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1835 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1836 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1837 if (ishdf5) { 1838 #if defined(PETSC_HAVE_HDF5) 1839 PetscViewerFormat format; 1840 PetscCall(PetscViewerGetFormat(viewer, &format)); 1841 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1842 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1843 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1844 #else 1845 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1846 #endif 1847 } 1848 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1849 PetscFunctionReturn(0); 1850 } 1851 1852 /*@ 1853 DMPlexLabelsView - Saves DMPlex labels into a file 1854 1855 Collective on DM 1856 1857 Input Parameters: 1858 + dm - The DM whose labels are to be saved 1859 - viewer - The PetscViewer for saving 1860 1861 Level: advanced 1862 1863 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1864 @*/ 1865 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1866 { 1867 PetscBool ishdf5; 1868 1869 PetscFunctionBegin; 1870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1871 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1872 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1873 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1874 if (ishdf5) { 1875 #if defined(PETSC_HAVE_HDF5) 1876 IS globalPointNumbering; 1877 PetscViewerFormat format; 1878 1879 PetscCall(PetscViewerGetFormat(viewer, &format)); 1880 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1881 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1882 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1883 PetscCall(ISDestroy(&globalPointNumbering)); 1884 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1885 #else 1886 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1887 #endif 1888 } 1889 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1890 PetscFunctionReturn(0); 1891 } 1892 1893 /*@ 1894 DMPlexSectionView - Saves a section associated with a DMPlex 1895 1896 Collective on DM 1897 1898 Input Parameters: 1899 + dm - The DM that contains the topology on which the section to be saved is defined 1900 . viewer - The PetscViewer for saving 1901 - sectiondm - The DM that contains the section to be saved 1902 1903 Level: advanced 1904 1905 Notes: 1906 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. 1907 1908 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. 1909 1910 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1911 @*/ 1912 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1913 { 1914 PetscBool ishdf5; 1915 1916 PetscFunctionBegin; 1917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1918 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1919 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1920 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1921 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1922 if (ishdf5) { 1923 #if defined(PETSC_HAVE_HDF5) 1924 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1925 #else 1926 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1927 #endif 1928 } 1929 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1930 PetscFunctionReturn(0); 1931 } 1932 1933 /*@ 1934 DMPlexGlobalVectorView - Saves a global vector 1935 1936 Collective on DM 1937 1938 Input Parameters: 1939 + dm - The DM that represents the topology 1940 . viewer - The PetscViewer to save data with 1941 . sectiondm - The DM that contains the global section on which vec is defined 1942 - vec - The global vector to be saved 1943 1944 Level: advanced 1945 1946 Notes: 1947 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. 1948 1949 Typical calling sequence 1950 $ DMCreate(PETSC_COMM_WORLD, &dm); 1951 $ DMSetType(dm, DMPLEX); 1952 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1953 $ DMClone(dm, §iondm); 1954 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1955 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1956 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1957 $ PetscSectionSetChart(section, pStart, pEnd); 1958 $ PetscSectionSetUp(section); 1959 $ DMSetLocalSection(sectiondm, section); 1960 $ PetscSectionDestroy(§ion); 1961 $ DMGetGlobalVector(sectiondm, &vec); 1962 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1963 $ DMPlexTopologyView(dm, viewer); 1964 $ DMPlexSectionView(dm, viewer, sectiondm); 1965 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1966 $ DMRestoreGlobalVector(sectiondm, &vec); 1967 $ DMDestroy(§iondm); 1968 $ DMDestroy(&dm); 1969 1970 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1971 @*/ 1972 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1973 { 1974 PetscBool ishdf5; 1975 1976 PetscFunctionBegin; 1977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1978 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1979 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1980 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1981 /* Check consistency */ 1982 { 1983 PetscSection section; 1984 PetscBool includesConstraints; 1985 PetscInt m, m1; 1986 1987 PetscCall(VecGetLocalSize(vec, &m1)); 1988 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1989 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1990 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1991 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1992 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1993 } 1994 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1995 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1996 if (ishdf5) { 1997 #if defined(PETSC_HAVE_HDF5) 1998 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1999 #else 2000 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2001 #endif 2002 } 2003 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 2004 PetscFunctionReturn(0); 2005 } 2006 2007 /*@ 2008 DMPlexLocalVectorView - Saves a local vector 2009 2010 Collective on DM 2011 2012 Input Parameters: 2013 + dm - The DM that represents the topology 2014 . viewer - The PetscViewer to save data with 2015 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2016 - vec - The local vector to be saved 2017 2018 Level: advanced 2019 2020 Notes: 2021 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. 2022 2023 Typical calling sequence 2024 $ DMCreate(PETSC_COMM_WORLD, &dm); 2025 $ DMSetType(dm, DMPLEX); 2026 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2027 $ DMClone(dm, §iondm); 2028 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2029 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2030 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2031 $ PetscSectionSetChart(section, pStart, pEnd); 2032 $ PetscSectionSetUp(section); 2033 $ DMSetLocalSection(sectiondm, section); 2034 $ DMGetLocalVector(sectiondm, &vec); 2035 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2036 $ DMPlexTopologyView(dm, viewer); 2037 $ DMPlexSectionView(dm, viewer, sectiondm); 2038 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2039 $ DMRestoreLocalVector(sectiondm, &vec); 2040 $ DMDestroy(§iondm); 2041 $ DMDestroy(&dm); 2042 2043 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2044 @*/ 2045 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2046 { 2047 PetscBool ishdf5; 2048 2049 PetscFunctionBegin; 2050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2051 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2052 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2053 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2054 /* Check consistency */ 2055 { 2056 PetscSection section; 2057 PetscBool includesConstraints; 2058 PetscInt m, m1; 2059 2060 PetscCall(VecGetLocalSize(vec, &m1)); 2061 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2062 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2063 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2064 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2065 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2066 } 2067 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2068 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2069 if (ishdf5) { 2070 #if defined(PETSC_HAVE_HDF5) 2071 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2077 PetscFunctionReturn(0); 2078 } 2079 2080 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2081 { 2082 PetscBool ishdf5; 2083 2084 PetscFunctionBegin; 2085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2086 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2087 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2088 if (ishdf5) { 2089 #if defined(PETSC_HAVE_HDF5) 2090 PetscViewerFormat format; 2091 PetscCall(PetscViewerGetFormat(viewer, &format)); 2092 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2093 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2094 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2095 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2096 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2097 PetscFunctionReturn(0); 2098 #else 2099 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2100 #endif 2101 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2102 } 2103 2104 /*@ 2105 DMPlexTopologyLoad - Loads a topology into a DMPlex 2106 2107 Collective on DM 2108 2109 Input Parameters: 2110 + dm - The DM into which the topology is loaded 2111 - viewer - The PetscViewer for the saved topology 2112 2113 Output Parameters: 2114 . 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 2115 2116 Level: advanced 2117 2118 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2119 @*/ 2120 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2121 { 2122 PetscBool ishdf5; 2123 2124 PetscFunctionBegin; 2125 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2126 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2127 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2128 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2129 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2130 if (ishdf5) { 2131 #if defined(PETSC_HAVE_HDF5) 2132 PetscViewerFormat format; 2133 PetscCall(PetscViewerGetFormat(viewer, &format)); 2134 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2135 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2136 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2137 #else 2138 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2139 #endif 2140 } 2141 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2142 PetscFunctionReturn(0); 2143 } 2144 2145 /*@ 2146 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2147 2148 Collective on DM 2149 2150 Input Parameters: 2151 + dm - The DM into which the coordinates are loaded 2152 . viewer - The PetscViewer for the saved coordinates 2153 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2154 2155 Level: advanced 2156 2157 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2158 @*/ 2159 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2160 { 2161 PetscBool ishdf5; 2162 2163 PetscFunctionBegin; 2164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2165 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2166 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2167 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2168 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2169 if (ishdf5) { 2170 #if defined(PETSC_HAVE_HDF5) 2171 PetscViewerFormat format; 2172 PetscCall(PetscViewerGetFormat(viewer, &format)); 2173 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2174 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2175 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2176 #else 2177 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2178 #endif 2179 } 2180 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2181 PetscFunctionReturn(0); 2182 } 2183 2184 /*@ 2185 DMPlexLabelsLoad - Loads labels into a DMPlex 2186 2187 Collective on DM 2188 2189 Input Parameters: 2190 + dm - The DM into which the labels are loaded 2191 . viewer - The PetscViewer for the saved labels 2192 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2193 2194 Level: advanced 2195 2196 Notes: 2197 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2198 2199 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2200 @*/ 2201 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2202 { 2203 PetscBool ishdf5; 2204 2205 PetscFunctionBegin; 2206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2207 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2208 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2209 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2210 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2211 if (ishdf5) { 2212 #if defined(PETSC_HAVE_HDF5) 2213 PetscViewerFormat format; 2214 2215 PetscCall(PetscViewerGetFormat(viewer, &format)); 2216 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2217 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2218 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2219 #else 2220 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2221 #endif 2222 } 2223 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2224 PetscFunctionReturn(0); 2225 } 2226 2227 /*@ 2228 DMPlexSectionLoad - Loads section into a DMPlex 2229 2230 Collective on DM 2231 2232 Input Parameters: 2233 + dm - The DM that represents the topology 2234 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2235 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2236 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2237 2238 Output Parameters 2239 + 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) 2240 - 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) 2241 2242 Level: advanced 2243 2244 Notes: 2245 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. 2246 2247 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. 2248 2249 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. 2250 2251 Example using 2 processes: 2252 $ NX (number of points on dm): 4 2253 $ sectionA : the on-disk section 2254 $ vecA : a vector associated with sectionA 2255 $ sectionB : sectiondm's local section constructed in this function 2256 $ vecB (local) : a vector associated with sectiondm's local section 2257 $ vecB (global) : a vector associated with sectiondm's global section 2258 $ 2259 $ rank 0 rank 1 2260 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2261 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2262 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2263 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2264 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2265 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2266 $ sectionB->atlasDof : 1 0 1 | 1 3 2267 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2268 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2269 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2270 $ 2271 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2272 2273 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2274 @*/ 2275 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2276 { 2277 PetscBool ishdf5; 2278 2279 PetscFunctionBegin; 2280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2281 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2282 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2283 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2284 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2285 if (localDofSF) PetscValidPointer(localDofSF, 6); 2286 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2287 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2288 if (ishdf5) { 2289 #if defined(PETSC_HAVE_HDF5) 2290 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2291 #else 2292 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2293 #endif 2294 } 2295 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2296 PetscFunctionReturn(0); 2297 } 2298 2299 /*@ 2300 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2301 2302 Collective on DM 2303 2304 Input Parameters: 2305 + dm - The DM that represents the topology 2306 . viewer - The PetscViewer that represents the on-disk vector data 2307 . sectiondm - The DM that contains the global section on which vec is defined 2308 . sf - The SF that migrates the on-disk vector data into vec 2309 - vec - The global vector to set values of 2310 2311 Level: advanced 2312 2313 Notes: 2314 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. 2315 2316 Typical calling sequence 2317 $ DMCreate(PETSC_COMM_WORLD, &dm); 2318 $ DMSetType(dm, DMPLEX); 2319 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2320 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2321 $ DMClone(dm, §iondm); 2322 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2323 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2324 $ DMGetGlobalVector(sectiondm, &vec); 2325 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2326 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2327 $ DMRestoreGlobalVector(sectiondm, &vec); 2328 $ PetscSFDestroy(&gsf); 2329 $ PetscSFDestroy(&sfX); 2330 $ DMDestroy(§iondm); 2331 $ DMDestroy(&dm); 2332 2333 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2334 @*/ 2335 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2336 { 2337 PetscBool ishdf5; 2338 2339 PetscFunctionBegin; 2340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2341 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2342 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2343 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2344 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2345 /* Check consistency */ 2346 { 2347 PetscSection section; 2348 PetscBool includesConstraints; 2349 PetscInt m, m1; 2350 2351 PetscCall(VecGetLocalSize(vec, &m1)); 2352 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2353 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2354 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2355 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2356 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2357 } 2358 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2359 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2360 if (ishdf5) { 2361 #if defined(PETSC_HAVE_HDF5) 2362 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2363 #else 2364 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2365 #endif 2366 } 2367 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2368 PetscFunctionReturn(0); 2369 } 2370 2371 /*@ 2372 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2373 2374 Collective on DM 2375 2376 Input Parameters: 2377 + dm - The DM that represents the topology 2378 . viewer - The PetscViewer that represents the on-disk vector data 2379 . sectiondm - The DM that contains the local section on which vec is defined 2380 . sf - The SF that migrates the on-disk vector data into vec 2381 - vec - The local vector to set values of 2382 2383 Level: advanced 2384 2385 Notes: 2386 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. 2387 2388 Typical calling sequence 2389 $ DMCreate(PETSC_COMM_WORLD, &dm); 2390 $ DMSetType(dm, DMPLEX); 2391 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2392 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2393 $ DMClone(dm, §iondm); 2394 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2395 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2396 $ DMGetLocalVector(sectiondm, &vec); 2397 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2398 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2399 $ DMRestoreLocalVector(sectiondm, &vec); 2400 $ PetscSFDestroy(&lsf); 2401 $ PetscSFDestroy(&sfX); 2402 $ DMDestroy(§iondm); 2403 $ DMDestroy(&dm); 2404 2405 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2406 @*/ 2407 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2408 { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2415 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 PetscErrorCode DMDestroy_Plex(DM dm) 2444 { 2445 DM_Plex *mesh = (DM_Plex*) dm->data; 2446 2447 PetscFunctionBegin; 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexSetOverlap_C",NULL)); 2461 if (--mesh->refct > 0) PetscFunctionReturn(0); 2462 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2463 PetscCall(PetscFree(mesh->cones)); 2464 PetscCall(PetscFree(mesh->coneOrientations)); 2465 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2466 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2467 PetscCall(PetscFree(mesh->supports)); 2468 PetscCall(PetscFree(mesh->facesTmp)); 2469 PetscCall(PetscFree(mesh->tetgenOpts)); 2470 PetscCall(PetscFree(mesh->triangleOpts)); 2471 PetscCall(PetscFree(mesh->transformType)); 2472 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2473 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2474 PetscCall(ISDestroy(&mesh->subpointIS)); 2475 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2476 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2477 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2478 PetscCall(ISDestroy(&mesh->anchorIS)); 2479 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2480 PetscCall(PetscFree(mesh->parents)); 2481 PetscCall(PetscFree(mesh->childIDs)); 2482 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2483 PetscCall(PetscFree(mesh->children)); 2484 PetscCall(DMDestroy(&mesh->referenceTree)); 2485 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2486 PetscCall(PetscFree(mesh->neighbors)); 2487 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2488 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2489 PetscCall(PetscFree(mesh)); 2490 PetscFunctionReturn(0); 2491 } 2492 2493 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2494 { 2495 PetscSection sectionGlobal; 2496 PetscInt bs = -1, mbs; 2497 PetscInt localSize, localStart = 0; 2498 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2499 MatType mtype; 2500 ISLocalToGlobalMapping ltog; 2501 2502 PetscFunctionBegin; 2503 PetscCall(MatInitializePackage()); 2504 mtype = dm->mattype; 2505 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2506 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2507 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2508 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2509 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2510 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2511 PetscCall(MatSetType(*J, mtype)); 2512 PetscCall(MatSetFromOptions(*J)); 2513 PetscCall(MatGetBlockSize(*J, &mbs)); 2514 if (mbs > 1) bs = mbs; 2515 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2516 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2522 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2523 if (!isShell) { 2524 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2525 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2526 PetscInt pStart, pEnd, p, dof, cdof; 2527 2528 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2529 2530 PetscCall(PetscCalloc1(localSize, &pblocks)); 2531 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2532 for (p = pStart; p < pEnd; ++p) { 2533 PetscInt bdof, offset; 2534 2535 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2536 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2537 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2538 for (PetscInt i=0; i < dof - cdof; i++) 2539 pblocks[offset - localStart + i] = dof - cdof; 2540 dof = dof < 0 ? -(dof+1) : dof; 2541 bdof = cdof && (dof-cdof) ? 1 : dof; 2542 if (dof) { 2543 if (bs < 0) {bs = bdof;} 2544 else if (bs != bdof) {bs = 1;} 2545 } 2546 } 2547 /* Must have same blocksize on all procs (some might have no points) */ 2548 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2549 bsLocal[1] = bs; 2550 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2551 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2552 else bs = bsMinMax[0]; 2553 bs = PetscMax(1,bs); 2554 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2555 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2556 PetscCall(MatSetBlockSize(*J, bs)); 2557 PetscCall(MatSetUp(*J)); 2558 } else { 2559 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2560 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2561 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2562 } 2563 { // Consolidate blocks 2564 PetscInt nblocks = 0; 2565 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2566 if (pblocks[i] == 0) continue; 2567 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2568 for (PetscInt j=1; j<pblocks[i]; j++) { 2569 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]); 2570 } 2571 } 2572 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2573 } 2574 PetscCall(PetscFree(pblocks)); 2575 } 2576 PetscCall(MatSetDM(*J, dm)); 2577 PetscFunctionReturn(0); 2578 } 2579 2580 /*@ 2581 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2582 2583 Not collective 2584 2585 Input Parameter: 2586 . mesh - The DMPlex 2587 2588 Output Parameters: 2589 . subsection - The subdomain section 2590 2591 Level: developer 2592 2593 .seealso: 2594 @*/ 2595 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2596 { 2597 DM_Plex *mesh = (DM_Plex*) dm->data; 2598 2599 PetscFunctionBegin; 2600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2601 if (!mesh->subdomainSection) { 2602 PetscSection section; 2603 PetscSF sf; 2604 2605 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2606 PetscCall(DMGetLocalSection(dm,§ion)); 2607 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2608 PetscCall(PetscSFDestroy(&sf)); 2609 } 2610 *subsection = mesh->subdomainSection; 2611 PetscFunctionReturn(0); 2612 } 2613 2614 /*@ 2615 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2616 2617 Not collective 2618 2619 Input Parameter: 2620 . mesh - The DMPlex 2621 2622 Output Parameters: 2623 + pStart - The first mesh point 2624 - pEnd - The upper bound for mesh points 2625 2626 Level: beginner 2627 2628 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2629 @*/ 2630 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2631 { 2632 DM_Plex *mesh = (DM_Plex*) dm->data; 2633 2634 PetscFunctionBegin; 2635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2636 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2637 PetscFunctionReturn(0); 2638 } 2639 2640 /*@ 2641 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2642 2643 Not collective 2644 2645 Input Parameters: 2646 + mesh - The DMPlex 2647 . pStart - The first mesh point 2648 - pEnd - The upper bound for mesh points 2649 2650 Output Parameters: 2651 2652 Level: beginner 2653 2654 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2655 @*/ 2656 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2657 { 2658 DM_Plex *mesh = (DM_Plex*) dm->data; 2659 2660 PetscFunctionBegin; 2661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2662 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2663 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2664 PetscFunctionReturn(0); 2665 } 2666 2667 /*@ 2668 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2669 2670 Not collective 2671 2672 Input Parameters: 2673 + mesh - The DMPlex 2674 - p - The point, which must lie in the chart set with DMPlexSetChart() 2675 2676 Output Parameter: 2677 . size - The cone size for point p 2678 2679 Level: beginner 2680 2681 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2682 @*/ 2683 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2684 { 2685 DM_Plex *mesh = (DM_Plex*) dm->data; 2686 2687 PetscFunctionBegin; 2688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2689 PetscValidIntPointer(size, 3); 2690 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2691 PetscFunctionReturn(0); 2692 } 2693 2694 /*@ 2695 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2696 2697 Not collective 2698 2699 Input Parameters: 2700 + mesh - The DMPlex 2701 . p - The point, which must lie in the chart set with DMPlexSetChart() 2702 - size - The cone size for point p 2703 2704 Output Parameter: 2705 2706 Note: 2707 This should be called after DMPlexSetChart(). 2708 2709 Level: beginner 2710 2711 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2712 @*/ 2713 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2714 { 2715 DM_Plex *mesh = (DM_Plex*) dm->data; 2716 2717 PetscFunctionBegin; 2718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2719 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2720 PetscFunctionReturn(0); 2721 } 2722 2723 /*@ 2724 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2725 2726 Not collective 2727 2728 Input Parameters: 2729 + mesh - The DMPlex 2730 . p - The point, which must lie in the chart set with DMPlexSetChart() 2731 - size - The additional cone size for point p 2732 2733 Output Parameter: 2734 2735 Note: 2736 This should be called after DMPlexSetChart(). 2737 2738 Level: beginner 2739 2740 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2741 @*/ 2742 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2743 { 2744 DM_Plex *mesh = (DM_Plex*) dm->data; 2745 PetscFunctionBegin; 2746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2747 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2748 PetscFunctionReturn(0); 2749 } 2750 2751 /*@C 2752 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2753 2754 Not collective 2755 2756 Input Parameters: 2757 + dm - The DMPlex 2758 - p - The point, which must lie in the chart set with DMPlexSetChart() 2759 2760 Output Parameter: 2761 . cone - An array of points which are on the in-edges for point p 2762 2763 Level: beginner 2764 2765 Fortran Notes: 2766 Since it returns an array, this routine is only available in Fortran 90, and you must 2767 include petsc.h90 in your code. 2768 You must also call DMPlexRestoreCone() after you finish using the returned array. 2769 DMPlexRestoreCone() is not needed/available in C. 2770 2771 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2772 @*/ 2773 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2774 { 2775 DM_Plex *mesh = (DM_Plex*) dm->data; 2776 PetscInt off; 2777 2778 PetscFunctionBegin; 2779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2780 PetscValidPointer(cone, 3); 2781 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2782 *cone = &mesh->cones[off]; 2783 PetscFunctionReturn(0); 2784 } 2785 2786 /*@C 2787 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2788 2789 Not collective 2790 2791 Input Parameters: 2792 + dm - The DMPlex 2793 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2794 2795 Output Parameters: 2796 + pConesSection - PetscSection describing the layout of pCones 2797 - pCones - An array of points which are on the in-edges for the point set p 2798 2799 Level: intermediate 2800 2801 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2802 @*/ 2803 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2804 { 2805 PetscSection cs, newcs; 2806 PetscInt *cones; 2807 PetscInt *newarr=NULL; 2808 PetscInt n; 2809 2810 PetscFunctionBegin; 2811 PetscCall(DMPlexGetCones(dm, &cones)); 2812 PetscCall(DMPlexGetConeSection(dm, &cs)); 2813 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2814 if (pConesSection) *pConesSection = newcs; 2815 if (pCones) { 2816 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2817 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2818 } 2819 PetscFunctionReturn(0); 2820 } 2821 2822 /*@ 2823 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2824 2825 Not collective 2826 2827 Input Parameters: 2828 + dm - The DMPlex 2829 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2830 2831 Output Parameter: 2832 . expandedPoints - An array of vertices recursively expanded from input points 2833 2834 Level: advanced 2835 2836 Notes: 2837 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2838 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2839 2840 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2841 @*/ 2842 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2843 { 2844 IS *expandedPointsAll; 2845 PetscInt depth; 2846 2847 PetscFunctionBegin; 2848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2849 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2850 PetscValidPointer(expandedPoints, 3); 2851 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2852 *expandedPoints = expandedPointsAll[0]; 2853 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2854 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2855 PetscFunctionReturn(0); 2856 } 2857 2858 /*@ 2859 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). 2860 2861 Not collective 2862 2863 Input Parameters: 2864 + dm - The DMPlex 2865 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2866 2867 Output Parameters: 2868 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2869 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2870 - sections - (optional) An array of sections which describe mappings from points to their cone points 2871 2872 Level: advanced 2873 2874 Notes: 2875 Like DMPlexGetConeTuple() but recursive. 2876 2877 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. 2878 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2879 2880 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: 2881 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2882 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2883 2884 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2885 @*/ 2886 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2887 { 2888 const PetscInt *arr0=NULL, *cone=NULL; 2889 PetscInt *arr=NULL, *newarr=NULL; 2890 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2891 IS *expandedPoints_; 2892 PetscSection *sections_; 2893 2894 PetscFunctionBegin; 2895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2896 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2897 if (depth) PetscValidIntPointer(depth, 3); 2898 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2899 if (sections) PetscValidPointer(sections, 5); 2900 PetscCall(ISGetLocalSize(points, &n)); 2901 PetscCall(ISGetIndices(points, &arr0)); 2902 PetscCall(DMPlexGetDepth(dm, &depth_)); 2903 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2904 PetscCall(PetscCalloc1(depth_, §ions_)); 2905 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2906 for (d=depth_-1; d>=0; d--) { 2907 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2908 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2909 for (i=0; i<n; i++) { 2910 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2911 if (arr[i] >= start && arr[i] < end) { 2912 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2913 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2914 } else { 2915 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2916 } 2917 } 2918 PetscCall(PetscSectionSetUp(sections_[d])); 2919 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2920 PetscCall(PetscMalloc1(newn, &newarr)); 2921 for (i=0; i<n; i++) { 2922 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2923 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2924 if (cn > 1) { 2925 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2926 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2927 } else { 2928 newarr[co] = arr[i]; 2929 } 2930 } 2931 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2932 arr = newarr; 2933 n = newn; 2934 } 2935 PetscCall(ISRestoreIndices(points, &arr0)); 2936 *depth = depth_; 2937 if (expandedPoints) *expandedPoints = expandedPoints_; 2938 else { 2939 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2940 PetscCall(PetscFree(expandedPoints_)); 2941 } 2942 if (sections) *sections = sections_; 2943 else { 2944 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2945 PetscCall(PetscFree(sections_)); 2946 } 2947 PetscFunctionReturn(0); 2948 } 2949 2950 /*@ 2951 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2952 2953 Not collective 2954 2955 Input Parameters: 2956 + dm - The DMPlex 2957 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2958 2959 Output Parameters: 2960 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2961 . expandedPoints - (optional) An array of recursively expanded cones 2962 - sections - (optional) An array of sections which describe mappings from points to their cone points 2963 2964 Level: advanced 2965 2966 Notes: 2967 See DMPlexGetConeRecursive() for details. 2968 2969 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2970 @*/ 2971 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2972 { 2973 PetscInt d, depth_; 2974 2975 PetscFunctionBegin; 2976 PetscCall(DMPlexGetDepth(dm, &depth_)); 2977 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2978 if (depth) *depth = 0; 2979 if (expandedPoints) { 2980 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2981 PetscCall(PetscFree(*expandedPoints)); 2982 } 2983 if (sections) { 2984 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2985 PetscCall(PetscFree(*sections)); 2986 } 2987 PetscFunctionReturn(0); 2988 } 2989 2990 /*@ 2991 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 2992 2993 Not collective 2994 2995 Input Parameters: 2996 + mesh - The DMPlex 2997 . p - The point, which must lie in the chart set with DMPlexSetChart() 2998 - cone - An array of points which are on the in-edges for point p 2999 3000 Output Parameter: 3001 3002 Note: 3003 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3004 3005 Level: beginner 3006 3007 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3008 @*/ 3009 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3010 { 3011 DM_Plex *mesh = (DM_Plex*) dm->data; 3012 PetscInt pStart, pEnd; 3013 PetscInt dof, off, c; 3014 3015 PetscFunctionBegin; 3016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3017 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3018 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3019 if (dof) PetscValidIntPointer(cone, 3); 3020 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3021 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); 3022 for (c = 0; c < dof; ++c) { 3023 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); 3024 mesh->cones[off+c] = cone[c]; 3025 } 3026 PetscFunctionReturn(0); 3027 } 3028 3029 /*@C 3030 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3031 3032 Not collective 3033 3034 Input Parameters: 3035 + mesh - The DMPlex 3036 - p - The point, which must lie in the chart set with DMPlexSetChart() 3037 3038 Output Parameter: 3039 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3040 integer giving the prescription for cone traversal. 3041 3042 Level: beginner 3043 3044 Notes: 3045 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3046 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3047 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3048 with the identity. 3049 3050 Fortran Notes: 3051 Since it returns an array, this routine is only available in Fortran 90, and you must 3052 include petsc.h90 in your code. 3053 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3054 DMPlexRestoreConeOrientation() is not needed/available in C. 3055 3056 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3057 @*/ 3058 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3059 { 3060 DM_Plex *mesh = (DM_Plex*) dm->data; 3061 PetscInt off; 3062 3063 PetscFunctionBegin; 3064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3065 if (PetscDefined(USE_DEBUG)) { 3066 PetscInt dof; 3067 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3068 if (dof) PetscValidPointer(coneOrientation, 3); 3069 } 3070 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3071 3072 *coneOrientation = &mesh->coneOrientations[off]; 3073 PetscFunctionReturn(0); 3074 } 3075 3076 /*@ 3077 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3078 3079 Not collective 3080 3081 Input Parameters: 3082 + mesh - The DMPlex 3083 . p - The point, which must lie in the chart set with DMPlexSetChart() 3084 - coneOrientation - An array of orientations 3085 Output Parameter: 3086 3087 Notes: 3088 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3089 3090 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3091 3092 Level: beginner 3093 3094 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3095 @*/ 3096 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3097 { 3098 DM_Plex *mesh = (DM_Plex*) dm->data; 3099 PetscInt pStart, pEnd; 3100 PetscInt dof, off, c; 3101 3102 PetscFunctionBegin; 3103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3104 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3105 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3106 if (dof) PetscValidIntPointer(coneOrientation, 3); 3107 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3108 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); 3109 for (c = 0; c < dof; ++c) { 3110 PetscInt cdof, o = coneOrientation[c]; 3111 3112 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3113 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); 3114 mesh->coneOrientations[off+c] = o; 3115 } 3116 PetscFunctionReturn(0); 3117 } 3118 3119 /*@ 3120 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3121 3122 Not collective 3123 3124 Input Parameters: 3125 + mesh - The DMPlex 3126 . p - The point, which must lie in the chart set with DMPlexSetChart() 3127 . conePos - The local index in the cone where the point should be put 3128 - conePoint - The mesh point to insert 3129 3130 Level: beginner 3131 3132 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3133 @*/ 3134 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3135 { 3136 DM_Plex *mesh = (DM_Plex*) dm->data; 3137 PetscInt pStart, pEnd; 3138 PetscInt dof, off; 3139 3140 PetscFunctionBegin; 3141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3142 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3143 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); 3144 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); 3145 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3146 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3147 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); 3148 mesh->cones[off+conePos] = conePoint; 3149 PetscFunctionReturn(0); 3150 } 3151 3152 /*@ 3153 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3154 3155 Not collective 3156 3157 Input Parameters: 3158 + mesh - The DMPlex 3159 . p - The point, which must lie in the chart set with DMPlexSetChart() 3160 . conePos - The local index in the cone where the point should be put 3161 - coneOrientation - The point orientation to insert 3162 3163 Level: beginner 3164 3165 Notes: 3166 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3167 3168 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3169 @*/ 3170 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3171 { 3172 DM_Plex *mesh = (DM_Plex*) dm->data; 3173 PetscInt pStart, pEnd; 3174 PetscInt dof, off; 3175 3176 PetscFunctionBegin; 3177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3178 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3179 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); 3180 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3181 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3182 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); 3183 mesh->coneOrientations[off+conePos] = coneOrientation; 3184 PetscFunctionReturn(0); 3185 } 3186 3187 /*@ 3188 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3189 3190 Not collective 3191 3192 Input Parameters: 3193 + mesh - The DMPlex 3194 - p - The point, which must lie in the chart set with DMPlexSetChart() 3195 3196 Output Parameter: 3197 . size - The support size for point p 3198 3199 Level: beginner 3200 3201 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3202 @*/ 3203 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3204 { 3205 DM_Plex *mesh = (DM_Plex*) dm->data; 3206 3207 PetscFunctionBegin; 3208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3209 PetscValidIntPointer(size, 3); 3210 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3211 PetscFunctionReturn(0); 3212 } 3213 3214 /*@ 3215 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3216 3217 Not collective 3218 3219 Input Parameters: 3220 + mesh - The DMPlex 3221 . p - The point, which must lie in the chart set with DMPlexSetChart() 3222 - size - The support size for point p 3223 3224 Output Parameter: 3225 3226 Note: 3227 This should be called after DMPlexSetChart(). 3228 3229 Level: beginner 3230 3231 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3232 @*/ 3233 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3234 { 3235 DM_Plex *mesh = (DM_Plex*) dm->data; 3236 3237 PetscFunctionBegin; 3238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3239 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3240 PetscFunctionReturn(0); 3241 } 3242 3243 /*@C 3244 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3245 3246 Not collective 3247 3248 Input Parameters: 3249 + mesh - The DMPlex 3250 - p - The point, which must lie in the chart set with DMPlexSetChart() 3251 3252 Output Parameter: 3253 . support - An array of points which are on the out-edges for point p 3254 3255 Level: beginner 3256 3257 Fortran Notes: 3258 Since it returns an array, this routine is only available in Fortran 90, and you must 3259 include petsc.h90 in your code. 3260 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3261 DMPlexRestoreSupport() is not needed/available in C. 3262 3263 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3264 @*/ 3265 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3266 { 3267 DM_Plex *mesh = (DM_Plex*) dm->data; 3268 PetscInt off; 3269 3270 PetscFunctionBegin; 3271 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3272 PetscValidPointer(support, 3); 3273 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3274 *support = &mesh->supports[off]; 3275 PetscFunctionReturn(0); 3276 } 3277 3278 /*@ 3279 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3280 3281 Not collective 3282 3283 Input Parameters: 3284 + mesh - The DMPlex 3285 . p - The point, which must lie in the chart set with DMPlexSetChart() 3286 - support - An array of points which are on the out-edges for point p 3287 3288 Output Parameter: 3289 3290 Note: 3291 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3292 3293 Level: beginner 3294 3295 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3296 @*/ 3297 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3298 { 3299 DM_Plex *mesh = (DM_Plex*) dm->data; 3300 PetscInt pStart, pEnd; 3301 PetscInt dof, off, c; 3302 3303 PetscFunctionBegin; 3304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3305 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3306 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3307 if (dof) PetscValidIntPointer(support, 3); 3308 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3309 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); 3310 for (c = 0; c < dof; ++c) { 3311 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); 3312 mesh->supports[off+c] = support[c]; 3313 } 3314 PetscFunctionReturn(0); 3315 } 3316 3317 /*@ 3318 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3319 3320 Not collective 3321 3322 Input Parameters: 3323 + mesh - The DMPlex 3324 . p - The point, which must lie in the chart set with DMPlexSetChart() 3325 . supportPos - The local index in the cone where the point should be put 3326 - supportPoint - The mesh point to insert 3327 3328 Level: beginner 3329 3330 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3331 @*/ 3332 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3333 { 3334 DM_Plex *mesh = (DM_Plex*) dm->data; 3335 PetscInt pStart, pEnd; 3336 PetscInt dof, off; 3337 3338 PetscFunctionBegin; 3339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3340 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3341 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3342 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3343 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); 3344 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); 3345 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); 3346 mesh->supports[off+supportPos] = supportPoint; 3347 PetscFunctionReturn(0); 3348 } 3349 3350 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3351 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3352 { 3353 switch (ct) { 3354 case DM_POLYTOPE_SEGMENT: 3355 if (o == -1) return -2; 3356 break; 3357 case DM_POLYTOPE_TRIANGLE: 3358 if (o == -3) return -1; 3359 if (o == -2) return -3; 3360 if (o == -1) return -2; 3361 break; 3362 case DM_POLYTOPE_QUADRILATERAL: 3363 if (o == -4) return -2; 3364 if (o == -3) return -1; 3365 if (o == -2) return -4; 3366 if (o == -1) return -3; 3367 break; 3368 default: return o; 3369 } 3370 return o; 3371 } 3372 3373 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3374 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3375 { 3376 switch (ct) { 3377 case DM_POLYTOPE_SEGMENT: 3378 if ((o == -2) || (o == 1)) return -1; 3379 if (o == -1) return 0; 3380 break; 3381 case DM_POLYTOPE_TRIANGLE: 3382 if (o == -3) return -2; 3383 if (o == -2) return -1; 3384 if (o == -1) return -3; 3385 break; 3386 case DM_POLYTOPE_QUADRILATERAL: 3387 if (o == -4) return -2; 3388 if (o == -3) return -1; 3389 if (o == -2) return -4; 3390 if (o == -1) return -3; 3391 break; 3392 default: return o; 3393 } 3394 return o; 3395 } 3396 3397 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3398 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3399 { 3400 PetscInt pStart, pEnd, p; 3401 3402 PetscFunctionBegin; 3403 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3404 for (p = pStart; p < pEnd; ++p) { 3405 const PetscInt *cone, *ornt; 3406 PetscInt coneSize, c; 3407 3408 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3409 PetscCall(DMPlexGetCone(dm, p, &cone)); 3410 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3411 for (c = 0; c < coneSize; ++c) { 3412 DMPolytopeType ct; 3413 const PetscInt o = ornt[c]; 3414 3415 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3416 switch (ct) { 3417 case DM_POLYTOPE_SEGMENT: 3418 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3419 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3420 break; 3421 case DM_POLYTOPE_TRIANGLE: 3422 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3423 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3424 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3425 break; 3426 case DM_POLYTOPE_QUADRILATERAL: 3427 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3428 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3429 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3430 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3431 break; 3432 default: break; 3433 } 3434 } 3435 } 3436 PetscFunctionReturn(0); 3437 } 3438 3439 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3440 { 3441 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3442 PetscInt *closure; 3443 const PetscInt *tmp = NULL, *tmpO = NULL; 3444 PetscInt off = 0, tmpSize, t; 3445 3446 PetscFunctionBeginHot; 3447 if (ornt) { 3448 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3449 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3450 } 3451 if (*points) { 3452 closure = *points; 3453 } else { 3454 PetscInt maxConeSize, maxSupportSize; 3455 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3456 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3457 } 3458 if (useCone) { 3459 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3460 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3461 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3462 } else { 3463 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3464 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3465 } 3466 if (ct == DM_POLYTOPE_UNKNOWN) { 3467 closure[off++] = p; 3468 closure[off++] = 0; 3469 for (t = 0; t < tmpSize; ++t) { 3470 closure[off++] = tmp[t]; 3471 closure[off++] = tmpO ? tmpO[t] : 0; 3472 } 3473 } else { 3474 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3475 3476 /* We assume that cells with a valid type have faces with a valid type */ 3477 closure[off++] = p; 3478 closure[off++] = ornt; 3479 for (t = 0; t < tmpSize; ++t) { 3480 DMPolytopeType ft; 3481 3482 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3483 closure[off++] = tmp[arr[t]]; 3484 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3485 } 3486 } 3487 if (numPoints) *numPoints = tmpSize+1; 3488 if (points) *points = closure; 3489 PetscFunctionReturn(0); 3490 } 3491 3492 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3493 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3494 { 3495 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3496 const PetscInt *cone, *ornt; 3497 PetscInt *pts, *closure = NULL; 3498 DMPolytopeType ft; 3499 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3500 PetscInt dim, coneSize, c, d, clSize, cl; 3501 3502 PetscFunctionBeginHot; 3503 PetscCall(DMGetDimension(dm, &dim)); 3504 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3505 PetscCall(DMPlexGetCone(dm, point, &cone)); 3506 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3507 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3508 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3509 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3510 maxSize = PetscMax(coneSeries, supportSeries); 3511 if (*points) {pts = *points;} 3512 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3513 c = 0; 3514 pts[c++] = point; 3515 pts[c++] = o; 3516 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3517 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3518 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3519 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3520 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3521 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3522 for (d = 2; d < coneSize; ++d) { 3523 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3524 pts[c++] = cone[arr[d*2+0]]; 3525 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3526 } 3527 if (dim >= 3) { 3528 for (d = 2; d < coneSize; ++d) { 3529 const PetscInt fpoint = cone[arr[d*2+0]]; 3530 const PetscInt *fcone, *fornt; 3531 PetscInt fconeSize, fc, i; 3532 3533 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3534 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3535 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3536 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3537 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3538 for (fc = 0; fc < fconeSize; ++fc) { 3539 const PetscInt cp = fcone[farr[fc*2+0]]; 3540 const PetscInt co = farr[fc*2+1]; 3541 3542 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3543 if (i == c) { 3544 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3545 pts[c++] = cp; 3546 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3547 } 3548 } 3549 } 3550 } 3551 *numPoints = c/2; 3552 *points = pts; 3553 PetscFunctionReturn(0); 3554 } 3555 3556 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3557 { 3558 DMPolytopeType ct; 3559 PetscInt *closure, *fifo; 3560 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3561 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3562 PetscInt depth, maxSize; 3563 3564 PetscFunctionBeginHot; 3565 PetscCall(DMPlexGetDepth(dm, &depth)); 3566 if (depth == 1) { 3567 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3568 PetscFunctionReturn(0); 3569 } 3570 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3571 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3572 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3573 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3574 PetscFunctionReturn(0); 3575 } 3576 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3577 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3578 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3579 maxSize = PetscMax(coneSeries, supportSeries); 3580 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3581 if (*points) {closure = *points;} 3582 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3583 closure[closureSize++] = p; 3584 closure[closureSize++] = ornt; 3585 fifo[fifoSize++] = p; 3586 fifo[fifoSize++] = ornt; 3587 fifo[fifoSize++] = ct; 3588 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3589 while (fifoSize - fifoStart) { 3590 const PetscInt q = fifo[fifoStart++]; 3591 const PetscInt o = fifo[fifoStart++]; 3592 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3593 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3594 const PetscInt *tmp, *tmpO; 3595 PetscInt tmpSize, t; 3596 3597 if (PetscDefined(USE_DEBUG)) { 3598 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3599 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); 3600 } 3601 if (useCone) { 3602 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3603 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3604 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3605 } else { 3606 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3607 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3608 tmpO = NULL; 3609 } 3610 for (t = 0; t < tmpSize; ++t) { 3611 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3612 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3613 const PetscInt cp = tmp[ip]; 3614 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3615 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3616 PetscInt c; 3617 3618 /* Check for duplicate */ 3619 for (c = 0; c < closureSize; c += 2) { 3620 if (closure[c] == cp) break; 3621 } 3622 if (c == closureSize) { 3623 closure[closureSize++] = cp; 3624 closure[closureSize++] = co; 3625 fifo[fifoSize++] = cp; 3626 fifo[fifoSize++] = co; 3627 fifo[fifoSize++] = ct; 3628 } 3629 } 3630 } 3631 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3632 if (numPoints) *numPoints = closureSize/2; 3633 if (points) *points = closure; 3634 PetscFunctionReturn(0); 3635 } 3636 3637 /*@C 3638 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3639 3640 Not collective 3641 3642 Input Parameters: 3643 + dm - The DMPlex 3644 . p - The mesh point 3645 - useCone - PETSC_TRUE for the closure, otherwise return the star 3646 3647 Input/Output Parameter: 3648 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3649 if NULL on input, internal storage will be returned, otherwise the provided array is used 3650 3651 Output Parameter: 3652 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3653 3654 Note: 3655 If using internal storage (points is NULL on input), each call overwrites the last output. 3656 3657 Fortran Notes: 3658 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3659 3660 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3661 3662 Level: beginner 3663 3664 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3665 @*/ 3666 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3667 { 3668 PetscFunctionBeginHot; 3669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3670 if (numPoints) PetscValidIntPointer(numPoints, 4); 3671 if (points) PetscValidPointer(points, 5); 3672 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3673 PetscFunctionReturn(0); 3674 } 3675 3676 /*@C 3677 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3678 3679 Not collective 3680 3681 Input Parameters: 3682 + dm - The DMPlex 3683 . p - The mesh point 3684 . useCone - PETSC_TRUE for the closure, otherwise return the star 3685 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3686 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3687 3688 Note: 3689 If not using internal storage (points is not NULL on input), this call is unnecessary 3690 3691 Fortran Notes: 3692 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3693 3694 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3695 3696 Level: beginner 3697 3698 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3699 @*/ 3700 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3701 { 3702 PetscFunctionBeginHot; 3703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3704 if (numPoints) *numPoints = 0; 3705 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3706 PetscFunctionReturn(0); 3707 } 3708 3709 /*@ 3710 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3711 3712 Not collective 3713 3714 Input Parameter: 3715 . mesh - The DMPlex 3716 3717 Output Parameters: 3718 + maxConeSize - The maximum number of in-edges 3719 - maxSupportSize - The maximum number of out-edges 3720 3721 Level: beginner 3722 3723 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3724 @*/ 3725 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3726 { 3727 DM_Plex *mesh = (DM_Plex*) dm->data; 3728 3729 PetscFunctionBegin; 3730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3731 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3732 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3733 PetscFunctionReturn(0); 3734 } 3735 3736 PetscErrorCode DMSetUp_Plex(DM dm) 3737 { 3738 DM_Plex *mesh = (DM_Plex*) dm->data; 3739 PetscInt size, maxSupportSize; 3740 3741 PetscFunctionBegin; 3742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3743 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3744 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3745 PetscCall(PetscMalloc1(size, &mesh->cones)); 3746 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3747 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3748 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3749 if (maxSupportSize) { 3750 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3751 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3752 PetscCall(PetscMalloc1(size, &mesh->supports)); 3753 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3754 } 3755 PetscFunctionReturn(0); 3756 } 3757 3758 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3759 { 3760 PetscFunctionBegin; 3761 if (subdm) PetscCall(DMClone(dm, subdm)); 3762 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3763 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3764 if (dm->useNatural && dm->sfMigration) { 3765 PetscSF sfMigrationInv,sfNatural; 3766 PetscSection section, sectionSeq; 3767 3768 (*subdm)->sfMigration = dm->sfMigration; 3769 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3770 PetscCall(DMGetLocalSection((*subdm), §ion)); 3771 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3772 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3773 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3774 3775 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3776 (*subdm)->sfNatural = sfNatural; 3777 PetscCall(PetscSectionDestroy(§ionSeq)); 3778 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3779 } 3780 PetscFunctionReturn(0); 3781 } 3782 3783 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3784 { 3785 PetscInt i = 0; 3786 3787 PetscFunctionBegin; 3788 PetscCall(DMClone(dms[0], superdm)); 3789 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3790 (*superdm)->useNatural = PETSC_FALSE; 3791 for (i = 0; i < len; i++) { 3792 if (dms[i]->useNatural && dms[i]->sfMigration) { 3793 PetscSF sfMigrationInv,sfNatural; 3794 PetscSection section, sectionSeq; 3795 3796 (*superdm)->sfMigration = dms[i]->sfMigration; 3797 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3798 (*superdm)->useNatural = PETSC_TRUE; 3799 PetscCall(DMGetLocalSection((*superdm), §ion)); 3800 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3801 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3802 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3803 3804 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3805 (*superdm)->sfNatural = sfNatural; 3806 PetscCall(PetscSectionDestroy(§ionSeq)); 3807 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3808 break; 3809 } 3810 } 3811 PetscFunctionReturn(0); 3812 } 3813 3814 /*@ 3815 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3816 3817 Not collective 3818 3819 Input Parameter: 3820 . mesh - The DMPlex 3821 3822 Output Parameter: 3823 3824 Note: 3825 This should be called after all calls to DMPlexSetCone() 3826 3827 Level: beginner 3828 3829 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3830 @*/ 3831 PetscErrorCode DMPlexSymmetrize(DM dm) 3832 { 3833 DM_Plex *mesh = (DM_Plex*) dm->data; 3834 PetscInt *offsets; 3835 PetscInt supportSize; 3836 PetscInt pStart, pEnd, p; 3837 3838 PetscFunctionBegin; 3839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3840 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3841 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3842 /* Calculate support sizes */ 3843 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3844 for (p = pStart; p < pEnd; ++p) { 3845 PetscInt dof, off, c; 3846 3847 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3848 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3849 for (c = off; c < off+dof; ++c) { 3850 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3851 } 3852 } 3853 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3854 /* Calculate supports */ 3855 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3856 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3857 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3858 for (p = pStart; p < pEnd; ++p) { 3859 PetscInt dof, off, c; 3860 3861 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3862 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3863 for (c = off; c < off+dof; ++c) { 3864 const PetscInt q = mesh->cones[c]; 3865 PetscInt offS; 3866 3867 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3868 3869 mesh->supports[offS+offsets[q]] = p; 3870 ++offsets[q]; 3871 } 3872 } 3873 PetscCall(PetscFree(offsets)); 3874 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3875 PetscFunctionReturn(0); 3876 } 3877 3878 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3879 { 3880 IS stratumIS; 3881 3882 PetscFunctionBegin; 3883 if (pStart >= pEnd) PetscFunctionReturn(0); 3884 if (PetscDefined(USE_DEBUG)) { 3885 PetscInt qStart, qEnd, numLevels, level; 3886 PetscBool overlap = PETSC_FALSE; 3887 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3888 for (level = 0; level < numLevels; level++) { 3889 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3890 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3891 } 3892 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); 3893 } 3894 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3895 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3896 PetscCall(ISDestroy(&stratumIS)); 3897 PetscFunctionReturn(0); 3898 } 3899 3900 /*@ 3901 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3902 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3903 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3904 the DAG. 3905 3906 Collective on dm 3907 3908 Input Parameter: 3909 . mesh - The DMPlex 3910 3911 Output Parameter: 3912 3913 Notes: 3914 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3915 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3916 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3917 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3918 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3919 3920 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3921 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3922 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 3923 to interpolate only that one (e0), so that 3924 $ cone(c0) = {e0, v2} 3925 $ cone(e0) = {v0, v1} 3926 If DMPlexStratify() is run on this mesh, it will give depths 3927 $ depth 0 = {v0, v1, v2} 3928 $ depth 1 = {e0, c0} 3929 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3930 3931 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3932 3933 Level: beginner 3934 3935 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3936 @*/ 3937 PetscErrorCode DMPlexStratify(DM dm) 3938 { 3939 DM_Plex *mesh = (DM_Plex*) dm->data; 3940 DMLabel label; 3941 PetscInt pStart, pEnd, p; 3942 PetscInt numRoots = 0, numLeaves = 0; 3943 3944 PetscFunctionBegin; 3945 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3946 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3947 3948 /* Create depth label */ 3949 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3950 PetscCall(DMCreateLabel(dm, "depth")); 3951 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3952 3953 { 3954 /* Initialize roots and count leaves */ 3955 PetscInt sMin = PETSC_MAX_INT; 3956 PetscInt sMax = PETSC_MIN_INT; 3957 PetscInt coneSize, supportSize; 3958 3959 for (p = pStart; p < pEnd; ++p) { 3960 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3961 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3962 if (!coneSize && supportSize) { 3963 sMin = PetscMin(p, sMin); 3964 sMax = PetscMax(p, sMax); 3965 ++numRoots; 3966 } else if (!supportSize && coneSize) { 3967 ++numLeaves; 3968 } else if (!supportSize && !coneSize) { 3969 /* Isolated points */ 3970 sMin = PetscMin(p, sMin); 3971 sMax = PetscMax(p, sMax); 3972 } 3973 } 3974 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3975 } 3976 3977 if (numRoots + numLeaves == (pEnd - pStart)) { 3978 PetscInt sMin = PETSC_MAX_INT; 3979 PetscInt sMax = PETSC_MIN_INT; 3980 PetscInt coneSize, supportSize; 3981 3982 for (p = pStart; p < pEnd; ++p) { 3983 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3984 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3985 if (!supportSize && coneSize) { 3986 sMin = PetscMin(p, sMin); 3987 sMax = PetscMax(p, sMax); 3988 } 3989 } 3990 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3991 } else { 3992 PetscInt level = 0; 3993 PetscInt qStart, qEnd, q; 3994 3995 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3996 while (qEnd > qStart) { 3997 PetscInt sMin = PETSC_MAX_INT; 3998 PetscInt sMax = PETSC_MIN_INT; 3999 4000 for (q = qStart; q < qEnd; ++q) { 4001 const PetscInt *support; 4002 PetscInt supportSize, s; 4003 4004 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4005 PetscCall(DMPlexGetSupport(dm, q, &support)); 4006 for (s = 0; s < supportSize; ++s) { 4007 sMin = PetscMin(support[s], sMin); 4008 sMax = PetscMax(support[s], sMax); 4009 } 4010 } 4011 PetscCall(DMLabelGetNumValues(label, &level)); 4012 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4013 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4014 } 4015 } 4016 { /* just in case there is an empty process */ 4017 PetscInt numValues, maxValues = 0, v; 4018 4019 PetscCall(DMLabelGetNumValues(label, &numValues)); 4020 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4021 for (v = numValues; v < maxValues; v++) { 4022 PetscCall(DMLabelAddStratum(label, v)); 4023 } 4024 } 4025 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4026 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4027 PetscFunctionReturn(0); 4028 } 4029 4030 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4031 { 4032 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4033 PetscInt dim, depth, pheight, coneSize; 4034 4035 PetscFunctionBeginHot; 4036 PetscCall(DMGetDimension(dm, &dim)); 4037 PetscCall(DMPlexGetDepth(dm, &depth)); 4038 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4039 pheight = depth - pdepth; 4040 if (depth <= 1) { 4041 switch (pdepth) { 4042 case 0: ct = DM_POLYTOPE_POINT;break; 4043 case 1: 4044 switch (coneSize) { 4045 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4046 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4047 case 4: 4048 switch (dim) { 4049 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4050 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4051 default: break; 4052 } 4053 break; 4054 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4055 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4056 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4057 default: break; 4058 } 4059 } 4060 } else { 4061 if (pdepth == 0) { 4062 ct = DM_POLYTOPE_POINT; 4063 } else if (pheight == 0) { 4064 switch (dim) { 4065 case 1: 4066 switch (coneSize) { 4067 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4068 default: break; 4069 } 4070 break; 4071 case 2: 4072 switch (coneSize) { 4073 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4074 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4075 default: break; 4076 } 4077 break; 4078 case 3: 4079 switch (coneSize) { 4080 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4081 case 5: 4082 { 4083 const PetscInt *cone; 4084 PetscInt faceConeSize; 4085 4086 PetscCall(DMPlexGetCone(dm, p, &cone)); 4087 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4088 switch (faceConeSize) { 4089 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4090 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4091 } 4092 } 4093 break; 4094 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4095 default: break; 4096 } 4097 break; 4098 default: break; 4099 } 4100 } else if (pheight > 0) { 4101 switch (coneSize) { 4102 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4103 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4104 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4105 default: break; 4106 } 4107 } 4108 } 4109 *pt = ct; 4110 PetscFunctionReturn(0); 4111 } 4112 4113 /*@ 4114 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4115 4116 Collective on dm 4117 4118 Input Parameter: 4119 . mesh - The DMPlex 4120 4121 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4122 4123 Level: developer 4124 4125 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4126 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4127 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4128 4129 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4130 @*/ 4131 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4132 { 4133 DM_Plex *mesh; 4134 DMLabel ctLabel; 4135 PetscInt pStart, pEnd, p; 4136 4137 PetscFunctionBegin; 4138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4139 mesh = (DM_Plex *) dm->data; 4140 PetscCall(DMCreateLabel(dm, "celltype")); 4141 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4142 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4143 for (p = pStart; p < pEnd; ++p) { 4144 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4145 PetscInt pdepth; 4146 4147 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4148 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4149 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4150 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4151 } 4152 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4153 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4154 PetscFunctionReturn(0); 4155 } 4156 4157 /*@C 4158 DMPlexGetJoin - Get an array for the join of the set of points 4159 4160 Not Collective 4161 4162 Input Parameters: 4163 + dm - The DMPlex object 4164 . numPoints - The number of input points for the join 4165 - points - The input points 4166 4167 Output Parameters: 4168 + numCoveredPoints - The number of points in the join 4169 - coveredPoints - The points in the join 4170 4171 Level: intermediate 4172 4173 Note: Currently, this is restricted to a single level join 4174 4175 Fortran Notes: 4176 Since it returns an array, this routine is only available in Fortran 90, and you must 4177 include petsc.h90 in your code. 4178 4179 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4180 4181 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4182 @*/ 4183 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4184 { 4185 DM_Plex *mesh = (DM_Plex*) dm->data; 4186 PetscInt *join[2]; 4187 PetscInt joinSize, i = 0; 4188 PetscInt dof, off, p, c, m; 4189 PetscInt maxSupportSize; 4190 4191 PetscFunctionBegin; 4192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4193 PetscValidIntPointer(points, 3); 4194 PetscValidIntPointer(numCoveredPoints, 4); 4195 PetscValidPointer(coveredPoints, 5); 4196 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4197 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4198 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4199 /* Copy in support of first point */ 4200 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4201 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4202 for (joinSize = 0; joinSize < dof; ++joinSize) { 4203 join[i][joinSize] = mesh->supports[off+joinSize]; 4204 } 4205 /* Check each successive support */ 4206 for (p = 1; p < numPoints; ++p) { 4207 PetscInt newJoinSize = 0; 4208 4209 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4210 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4211 for (c = 0; c < dof; ++c) { 4212 const PetscInt point = mesh->supports[off+c]; 4213 4214 for (m = 0; m < joinSize; ++m) { 4215 if (point == join[i][m]) { 4216 join[1-i][newJoinSize++] = point; 4217 break; 4218 } 4219 } 4220 } 4221 joinSize = newJoinSize; 4222 i = 1-i; 4223 } 4224 *numCoveredPoints = joinSize; 4225 *coveredPoints = join[i]; 4226 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4227 PetscFunctionReturn(0); 4228 } 4229 4230 /*@C 4231 DMPlexRestoreJoin - Restore an array for the join of the set of points 4232 4233 Not Collective 4234 4235 Input Parameters: 4236 + dm - The DMPlex object 4237 . numPoints - The number of input points for the join 4238 - points - The input points 4239 4240 Output Parameters: 4241 + numCoveredPoints - The number of points in the join 4242 - coveredPoints - The points in the join 4243 4244 Fortran Notes: 4245 Since it returns an array, this routine is only available in Fortran 90, and you must 4246 include petsc.h90 in your code. 4247 4248 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4249 4250 Level: intermediate 4251 4252 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4253 @*/ 4254 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4255 { 4256 PetscFunctionBegin; 4257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4258 if (points) PetscValidIntPointer(points,3); 4259 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4260 PetscValidPointer(coveredPoints, 5); 4261 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4262 if (numCoveredPoints) *numCoveredPoints = 0; 4263 PetscFunctionReturn(0); 4264 } 4265 4266 /*@C 4267 DMPlexGetFullJoin - Get an array for the join of the set of points 4268 4269 Not Collective 4270 4271 Input Parameters: 4272 + dm - The DMPlex object 4273 . numPoints - The number of input points for the join 4274 - points - The input points 4275 4276 Output Parameters: 4277 + numCoveredPoints - The number of points in the join 4278 - coveredPoints - The points in the join 4279 4280 Fortran Notes: 4281 Since it returns an array, this routine is only available in Fortran 90, and you must 4282 include petsc.h90 in your code. 4283 4284 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4285 4286 Level: intermediate 4287 4288 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4289 @*/ 4290 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4291 { 4292 PetscInt *offsets, **closures; 4293 PetscInt *join[2]; 4294 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4295 PetscInt p, d, c, m, ms; 4296 4297 PetscFunctionBegin; 4298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4299 PetscValidIntPointer(points, 3); 4300 PetscValidIntPointer(numCoveredPoints, 4); 4301 PetscValidPointer(coveredPoints, 5); 4302 4303 PetscCall(DMPlexGetDepth(dm, &depth)); 4304 PetscCall(PetscCalloc1(numPoints, &closures)); 4305 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4306 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4307 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4308 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4309 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4310 4311 for (p = 0; p < numPoints; ++p) { 4312 PetscInt closureSize; 4313 4314 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4315 4316 offsets[p*(depth+2)+0] = 0; 4317 for (d = 0; d < depth+1; ++d) { 4318 PetscInt pStart, pEnd, i; 4319 4320 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4321 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4322 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4323 offsets[p*(depth+2)+d+1] = i; 4324 break; 4325 } 4326 } 4327 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4328 } 4329 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); 4330 } 4331 for (d = 0; d < depth+1; ++d) { 4332 PetscInt dof; 4333 4334 /* Copy in support of first point */ 4335 dof = offsets[d+1] - offsets[d]; 4336 for (joinSize = 0; joinSize < dof; ++joinSize) { 4337 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4338 } 4339 /* Check each successive cone */ 4340 for (p = 1; p < numPoints && joinSize; ++p) { 4341 PetscInt newJoinSize = 0; 4342 4343 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4344 for (c = 0; c < dof; ++c) { 4345 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4346 4347 for (m = 0; m < joinSize; ++m) { 4348 if (point == join[i][m]) { 4349 join[1-i][newJoinSize++] = point; 4350 break; 4351 } 4352 } 4353 } 4354 joinSize = newJoinSize; 4355 i = 1-i; 4356 } 4357 if (joinSize) break; 4358 } 4359 *numCoveredPoints = joinSize; 4360 *coveredPoints = join[i]; 4361 for (p = 0; p < numPoints; ++p) { 4362 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4363 } 4364 PetscCall(PetscFree(closures)); 4365 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4366 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4367 PetscFunctionReturn(0); 4368 } 4369 4370 /*@C 4371 DMPlexGetMeet - Get an array for the meet of the set of points 4372 4373 Not Collective 4374 4375 Input Parameters: 4376 + dm - The DMPlex object 4377 . numPoints - The number of input points for the meet 4378 - points - The input points 4379 4380 Output Parameters: 4381 + numCoveredPoints - The number of points in the meet 4382 - coveredPoints - The points in the meet 4383 4384 Level: intermediate 4385 4386 Note: Currently, this is restricted to a single level meet 4387 4388 Fortran Notes: 4389 Since it returns an array, this routine is only available in Fortran 90, and you must 4390 include petsc.h90 in your code. 4391 4392 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4393 4394 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4395 @*/ 4396 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4397 { 4398 DM_Plex *mesh = (DM_Plex*) dm->data; 4399 PetscInt *meet[2]; 4400 PetscInt meetSize, i = 0; 4401 PetscInt dof, off, p, c, m; 4402 PetscInt maxConeSize; 4403 4404 PetscFunctionBegin; 4405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4406 PetscValidIntPointer(points, 3); 4407 PetscValidIntPointer(numCoveringPoints, 4); 4408 PetscValidPointer(coveringPoints, 5); 4409 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4410 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4411 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4412 /* Copy in cone of first point */ 4413 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4414 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4415 for (meetSize = 0; meetSize < dof; ++meetSize) { 4416 meet[i][meetSize] = mesh->cones[off+meetSize]; 4417 } 4418 /* Check each successive cone */ 4419 for (p = 1; p < numPoints; ++p) { 4420 PetscInt newMeetSize = 0; 4421 4422 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4423 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4424 for (c = 0; c < dof; ++c) { 4425 const PetscInt point = mesh->cones[off+c]; 4426 4427 for (m = 0; m < meetSize; ++m) { 4428 if (point == meet[i][m]) { 4429 meet[1-i][newMeetSize++] = point; 4430 break; 4431 } 4432 } 4433 } 4434 meetSize = newMeetSize; 4435 i = 1-i; 4436 } 4437 *numCoveringPoints = meetSize; 4438 *coveringPoints = meet[i]; 4439 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4440 PetscFunctionReturn(0); 4441 } 4442 4443 /*@C 4444 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4445 4446 Not Collective 4447 4448 Input Parameters: 4449 + dm - The DMPlex object 4450 . numPoints - The number of input points for the meet 4451 - points - The input points 4452 4453 Output Parameters: 4454 + numCoveredPoints - The number of points in the meet 4455 - coveredPoints - The points in the meet 4456 4457 Level: intermediate 4458 4459 Fortran Notes: 4460 Since it returns an array, this routine is only available in Fortran 90, and you must 4461 include petsc.h90 in your code. 4462 4463 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4464 4465 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4466 @*/ 4467 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4468 { 4469 PetscFunctionBegin; 4470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4471 if (points) PetscValidIntPointer(points,3); 4472 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4473 PetscValidPointer(coveredPoints,5); 4474 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4475 if (numCoveredPoints) *numCoveredPoints = 0; 4476 PetscFunctionReturn(0); 4477 } 4478 4479 /*@C 4480 DMPlexGetFullMeet - Get an array for the meet of the set of points 4481 4482 Not Collective 4483 4484 Input Parameters: 4485 + dm - The DMPlex object 4486 . numPoints - The number of input points for the meet 4487 - points - The input points 4488 4489 Output Parameters: 4490 + numCoveredPoints - The number of points in the meet 4491 - coveredPoints - The points in the meet 4492 4493 Level: intermediate 4494 4495 Fortran Notes: 4496 Since it returns an array, this routine is only available in Fortran 90, and you must 4497 include petsc.h90 in your code. 4498 4499 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4500 4501 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4502 @*/ 4503 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4504 { 4505 PetscInt *offsets, **closures; 4506 PetscInt *meet[2]; 4507 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4508 PetscInt p, h, c, m, mc; 4509 4510 PetscFunctionBegin; 4511 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4512 PetscValidIntPointer(points, 3); 4513 PetscValidIntPointer(numCoveredPoints, 4); 4514 PetscValidPointer(coveredPoints, 5); 4515 4516 PetscCall(DMPlexGetDepth(dm, &height)); 4517 PetscCall(PetscMalloc1(numPoints, &closures)); 4518 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4519 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4520 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4521 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4522 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4523 4524 for (p = 0; p < numPoints; ++p) { 4525 PetscInt closureSize; 4526 4527 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4528 4529 offsets[p*(height+2)+0] = 0; 4530 for (h = 0; h < height+1; ++h) { 4531 PetscInt pStart, pEnd, i; 4532 4533 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4534 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4535 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4536 offsets[p*(height+2)+h+1] = i; 4537 break; 4538 } 4539 } 4540 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4541 } 4542 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); 4543 } 4544 for (h = 0; h < height+1; ++h) { 4545 PetscInt dof; 4546 4547 /* Copy in cone of first point */ 4548 dof = offsets[h+1] - offsets[h]; 4549 for (meetSize = 0; meetSize < dof; ++meetSize) { 4550 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4551 } 4552 /* Check each successive cone */ 4553 for (p = 1; p < numPoints && meetSize; ++p) { 4554 PetscInt newMeetSize = 0; 4555 4556 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4557 for (c = 0; c < dof; ++c) { 4558 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4559 4560 for (m = 0; m < meetSize; ++m) { 4561 if (point == meet[i][m]) { 4562 meet[1-i][newMeetSize++] = point; 4563 break; 4564 } 4565 } 4566 } 4567 meetSize = newMeetSize; 4568 i = 1-i; 4569 } 4570 if (meetSize) break; 4571 } 4572 *numCoveredPoints = meetSize; 4573 *coveredPoints = meet[i]; 4574 for (p = 0; p < numPoints; ++p) { 4575 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4576 } 4577 PetscCall(PetscFree(closures)); 4578 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4579 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4580 PetscFunctionReturn(0); 4581 } 4582 4583 /*@C 4584 DMPlexEqual - Determine if two DMs have the same topology 4585 4586 Not Collective 4587 4588 Input Parameters: 4589 + dmA - A DMPlex object 4590 - dmB - A DMPlex object 4591 4592 Output Parameters: 4593 . equal - PETSC_TRUE if the topologies are identical 4594 4595 Level: intermediate 4596 4597 Notes: 4598 We are not solving graph isomorphism, so we do not permutation. 4599 4600 .seealso: `DMPlexGetCone()` 4601 @*/ 4602 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4603 { 4604 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4605 4606 PetscFunctionBegin; 4607 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4608 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4609 PetscValidBoolPointer(equal, 3); 4610 4611 *equal = PETSC_FALSE; 4612 PetscCall(DMPlexGetDepth(dmA, &depth)); 4613 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4614 if (depth != depthB) PetscFunctionReturn(0); 4615 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4616 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4617 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4618 for (p = pStart; p < pEnd; ++p) { 4619 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4620 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4621 4622 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4623 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4624 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4625 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4626 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4627 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4628 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4629 for (c = 0; c < coneSize; ++c) { 4630 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4631 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4632 } 4633 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4634 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4635 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4636 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4637 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4638 for (s = 0; s < supportSize; ++s) { 4639 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4640 } 4641 } 4642 *equal = PETSC_TRUE; 4643 PetscFunctionReturn(0); 4644 } 4645 4646 /*@C 4647 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4648 4649 Not Collective 4650 4651 Input Parameters: 4652 + dm - The DMPlex 4653 . cellDim - The cell dimension 4654 - numCorners - The number of vertices on a cell 4655 4656 Output Parameters: 4657 . numFaceVertices - The number of vertices on a face 4658 4659 Level: developer 4660 4661 Notes: 4662 Of course this can only work for a restricted set of symmetric shapes 4663 4664 .seealso: `DMPlexGetCone()` 4665 @*/ 4666 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4667 { 4668 MPI_Comm comm; 4669 4670 PetscFunctionBegin; 4671 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4672 PetscValidIntPointer(numFaceVertices,4); 4673 switch (cellDim) { 4674 case 0: 4675 *numFaceVertices = 0; 4676 break; 4677 case 1: 4678 *numFaceVertices = 1; 4679 break; 4680 case 2: 4681 switch (numCorners) { 4682 case 3: /* triangle */ 4683 *numFaceVertices = 2; /* Edge has 2 vertices */ 4684 break; 4685 case 4: /* quadrilateral */ 4686 *numFaceVertices = 2; /* Edge has 2 vertices */ 4687 break; 4688 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4689 *numFaceVertices = 3; /* Edge has 3 vertices */ 4690 break; 4691 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4692 *numFaceVertices = 3; /* Edge has 3 vertices */ 4693 break; 4694 default: 4695 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4696 } 4697 break; 4698 case 3: 4699 switch (numCorners) { 4700 case 4: /* tetradehdron */ 4701 *numFaceVertices = 3; /* Face has 3 vertices */ 4702 break; 4703 case 6: /* tet cohesive cells */ 4704 *numFaceVertices = 4; /* Face has 4 vertices */ 4705 break; 4706 case 8: /* hexahedron */ 4707 *numFaceVertices = 4; /* Face has 4 vertices */ 4708 break; 4709 case 9: /* tet cohesive Lagrange cells */ 4710 *numFaceVertices = 6; /* Face has 6 vertices */ 4711 break; 4712 case 10: /* quadratic tetrahedron */ 4713 *numFaceVertices = 6; /* Face has 6 vertices */ 4714 break; 4715 case 12: /* hex cohesive Lagrange cells */ 4716 *numFaceVertices = 6; /* Face has 6 vertices */ 4717 break; 4718 case 18: /* quadratic tet cohesive Lagrange cells */ 4719 *numFaceVertices = 6; /* Face has 6 vertices */ 4720 break; 4721 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4722 *numFaceVertices = 9; /* Face has 9 vertices */ 4723 break; 4724 default: 4725 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4726 } 4727 break; 4728 default: 4729 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4730 } 4731 PetscFunctionReturn(0); 4732 } 4733 4734 /*@ 4735 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4736 4737 Not Collective 4738 4739 Input Parameter: 4740 . dm - The DMPlex object 4741 4742 Output Parameter: 4743 . depthLabel - The DMLabel recording point depth 4744 4745 Level: developer 4746 4747 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4748 @*/ 4749 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4750 { 4751 PetscFunctionBegin; 4752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4753 PetscValidPointer(depthLabel, 2); 4754 *depthLabel = dm->depthLabel; 4755 PetscFunctionReturn(0); 4756 } 4757 4758 /*@ 4759 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4760 4761 Not Collective 4762 4763 Input Parameter: 4764 . dm - The DMPlex object 4765 4766 Output Parameter: 4767 . depth - The number of strata (breadth first levels) in the DAG 4768 4769 Level: developer 4770 4771 Notes: 4772 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4773 The point depth is described more in detail in DMPlexGetDepthStratum(). 4774 An empty mesh gives -1. 4775 4776 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4777 @*/ 4778 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4779 { 4780 DMLabel label; 4781 PetscInt d = 0; 4782 4783 PetscFunctionBegin; 4784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4785 PetscValidIntPointer(depth, 2); 4786 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4787 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4788 *depth = d-1; 4789 PetscFunctionReturn(0); 4790 } 4791 4792 /*@ 4793 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4794 4795 Not Collective 4796 4797 Input Parameters: 4798 + dm - The DMPlex object 4799 - depth - The requested depth 4800 4801 Output Parameters: 4802 + start - The first point at this depth 4803 - end - One beyond the last point at this depth 4804 4805 Notes: 4806 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4807 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4808 higher dimension, e.g., "edges". 4809 4810 Level: developer 4811 4812 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4813 @*/ 4814 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4815 { 4816 DMLabel label; 4817 PetscInt pStart, pEnd; 4818 4819 PetscFunctionBegin; 4820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4821 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4822 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4823 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4824 if (pStart == pEnd) PetscFunctionReturn(0); 4825 if (depth < 0) { 4826 if (start) *start = pStart; 4827 if (end) *end = pEnd; 4828 PetscFunctionReturn(0); 4829 } 4830 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4831 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4832 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4833 PetscFunctionReturn(0); 4834 } 4835 4836 /*@ 4837 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4838 4839 Not Collective 4840 4841 Input Parameters: 4842 + dm - The DMPlex object 4843 - height - The requested height 4844 4845 Output Parameters: 4846 + start - The first point at this height 4847 - end - One beyond the last point at this height 4848 4849 Notes: 4850 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4851 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4852 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4853 4854 Level: developer 4855 4856 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4857 @*/ 4858 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4859 { 4860 DMLabel label; 4861 PetscInt depth, pStart, pEnd; 4862 4863 PetscFunctionBegin; 4864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4865 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4866 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4867 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4868 if (pStart == pEnd) PetscFunctionReturn(0); 4869 if (height < 0) { 4870 if (start) *start = pStart; 4871 if (end) *end = pEnd; 4872 PetscFunctionReturn(0); 4873 } 4874 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4875 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4876 PetscCall(DMLabelGetNumValues(label, &depth)); 4877 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4878 PetscFunctionReturn(0); 4879 } 4880 4881 /*@ 4882 DMPlexGetPointDepth - Get the depth of a given point 4883 4884 Not Collective 4885 4886 Input Parameters: 4887 + dm - The DMPlex object 4888 - point - The point 4889 4890 Output Parameter: 4891 . depth - The depth of the point 4892 4893 Level: intermediate 4894 4895 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4896 @*/ 4897 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4898 { 4899 PetscFunctionBegin; 4900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4901 PetscValidIntPointer(depth, 3); 4902 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4903 PetscFunctionReturn(0); 4904 } 4905 4906 /*@ 4907 DMPlexGetPointHeight - Get the height of a given point 4908 4909 Not Collective 4910 4911 Input Parameters: 4912 + dm - The DMPlex object 4913 - point - The point 4914 4915 Output Parameter: 4916 . height - The height of the point 4917 4918 Level: intermediate 4919 4920 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4921 @*/ 4922 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4923 { 4924 PetscInt n, pDepth; 4925 4926 PetscFunctionBegin; 4927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4928 PetscValidIntPointer(height, 3); 4929 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4930 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4931 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4932 PetscFunctionReturn(0); 4933 } 4934 4935 /*@ 4936 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4937 4938 Not Collective 4939 4940 Input Parameter: 4941 . dm - The DMPlex object 4942 4943 Output Parameter: 4944 . celltypeLabel - The DMLabel recording cell polytope type 4945 4946 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4947 DMCreateLabel(dm, "celltype") beforehand. 4948 4949 Level: developer 4950 4951 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4952 @*/ 4953 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4954 { 4955 PetscFunctionBegin; 4956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4957 PetscValidPointer(celltypeLabel, 2); 4958 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4959 *celltypeLabel = dm->celltypeLabel; 4960 PetscFunctionReturn(0); 4961 } 4962 4963 /*@ 4964 DMPlexGetCellType - Get the polytope type of a given cell 4965 4966 Not Collective 4967 4968 Input Parameters: 4969 + dm - The DMPlex object 4970 - cell - The cell 4971 4972 Output Parameter: 4973 . celltype - The polytope type of the cell 4974 4975 Level: intermediate 4976 4977 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4978 @*/ 4979 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4980 { 4981 DMLabel label; 4982 PetscInt ct; 4983 4984 PetscFunctionBegin; 4985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4986 PetscValidPointer(celltype, 3); 4987 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4988 PetscCall(DMLabelGetValue(label, cell, &ct)); 4989 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4990 *celltype = (DMPolytopeType) ct; 4991 PetscFunctionReturn(0); 4992 } 4993 4994 /*@ 4995 DMPlexSetCellType - Set the polytope type of a given cell 4996 4997 Not Collective 4998 4999 Input Parameters: 5000 + dm - The DMPlex object 5001 . cell - The cell 5002 - celltype - The polytope type of the cell 5003 5004 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5005 is executed. This function will override the computed type. However, if automatic classification will not succeed 5006 and a user wants to manually specify all types, the classification must be disabled by calling 5007 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5008 5009 Level: advanced 5010 5011 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5012 @*/ 5013 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5014 { 5015 DMLabel label; 5016 5017 PetscFunctionBegin; 5018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5019 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5020 PetscCall(DMLabelSetValue(label, cell, celltype)); 5021 PetscFunctionReturn(0); 5022 } 5023 5024 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5025 { 5026 PetscSection section, s; 5027 Mat m; 5028 PetscInt maxHeight; 5029 5030 PetscFunctionBegin; 5031 PetscCall(DMClone(dm, cdm)); 5032 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5033 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5034 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5035 PetscCall(DMSetLocalSection(*cdm, section)); 5036 PetscCall(PetscSectionDestroy(§ion)); 5037 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5038 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5039 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5040 PetscCall(PetscSectionDestroy(&s)); 5041 PetscCall(MatDestroy(&m)); 5042 5043 PetscCall(DMSetNumFields(*cdm, 1)); 5044 PetscCall(DMCreateDS(*cdm)); 5045 PetscFunctionReturn(0); 5046 } 5047 5048 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5049 { 5050 Vec coordsLocal, cellCoordsLocal; 5051 DM coordsDM, cellCoordsDM; 5052 5053 PetscFunctionBegin; 5054 *field = NULL; 5055 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5056 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5057 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5058 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5059 if (coordsLocal && coordsDM) { 5060 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5061 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5062 } 5063 PetscFunctionReturn(0); 5064 } 5065 5066 /*@C 5067 DMPlexGetConeSection - Return a section which describes the layout of cone data 5068 5069 Not Collective 5070 5071 Input Parameters: 5072 . dm - The DMPlex object 5073 5074 Output Parameter: 5075 . section - The PetscSection object 5076 5077 Level: developer 5078 5079 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5080 @*/ 5081 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5082 { 5083 DM_Plex *mesh = (DM_Plex*) dm->data; 5084 5085 PetscFunctionBegin; 5086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5087 if (section) *section = mesh->coneSection; 5088 PetscFunctionReturn(0); 5089 } 5090 5091 /*@C 5092 DMPlexGetSupportSection - Return a section which describes the layout of support data 5093 5094 Not Collective 5095 5096 Input Parameters: 5097 . dm - The DMPlex object 5098 5099 Output Parameter: 5100 . section - The PetscSection object 5101 5102 Level: developer 5103 5104 .seealso: `DMPlexGetConeSection()` 5105 @*/ 5106 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5107 { 5108 DM_Plex *mesh = (DM_Plex*) dm->data; 5109 5110 PetscFunctionBegin; 5111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5112 if (section) *section = mesh->supportSection; 5113 PetscFunctionReturn(0); 5114 } 5115 5116 /*@C 5117 DMPlexGetCones - Return cone data 5118 5119 Not Collective 5120 5121 Input Parameters: 5122 . dm - The DMPlex object 5123 5124 Output Parameter: 5125 . cones - The cone for each point 5126 5127 Level: developer 5128 5129 .seealso: `DMPlexGetConeSection()` 5130 @*/ 5131 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5132 { 5133 DM_Plex *mesh = (DM_Plex*) dm->data; 5134 5135 PetscFunctionBegin; 5136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5137 if (cones) *cones = mesh->cones; 5138 PetscFunctionReturn(0); 5139 } 5140 5141 /*@C 5142 DMPlexGetConeOrientations - Return cone orientation data 5143 5144 Not Collective 5145 5146 Input Parameters: 5147 . dm - The DMPlex object 5148 5149 Output Parameter: 5150 . coneOrientations - The array of cone orientations for all points 5151 5152 Level: developer 5153 5154 Notes: 5155 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5156 5157 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5158 5159 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5160 @*/ 5161 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5162 { 5163 DM_Plex *mesh = (DM_Plex*) dm->data; 5164 5165 PetscFunctionBegin; 5166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5167 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5168 PetscFunctionReturn(0); 5169 } 5170 5171 /******************************** FEM Support **********************************/ 5172 5173 /* 5174 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5175 representing a line in the section. 5176 */ 5177 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5178 { 5179 PetscFunctionBeginHot; 5180 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5181 if (line < 0) { 5182 *k = 0; 5183 *Nc = 0; 5184 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5185 *k = 1; 5186 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5187 /* An order k SEM disc has k-1 dofs on an edge */ 5188 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5189 *k = *k / *Nc + 1; 5190 } 5191 PetscFunctionReturn(0); 5192 } 5193 5194 /*@ 5195 5196 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5197 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5198 section provided (or the section of the DM). 5199 5200 Input Parameters: 5201 + dm - The DM 5202 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5203 - section - The PetscSection to reorder, or NULL for the default section 5204 5205 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5206 degree of the basis. 5207 5208 Example: 5209 A typical interpolated single-quad mesh might order points as 5210 .vb 5211 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5212 5213 v4 -- e6 -- v3 5214 | | 5215 e7 c0 e8 5216 | | 5217 v1 -- e5 -- v2 5218 .ve 5219 5220 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5221 dofs in the order of points, e.g., 5222 .vb 5223 c0 -> [0,1,2,3] 5224 v1 -> [4] 5225 ... 5226 e5 -> [8, 9] 5227 .ve 5228 5229 which corresponds to the dofs 5230 .vb 5231 6 10 11 7 5232 13 2 3 15 5233 12 0 1 14 5234 4 8 9 5 5235 .ve 5236 5237 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5238 .vb 5239 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5240 .ve 5241 5242 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5243 .vb 5244 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5245 .ve 5246 5247 Level: developer 5248 5249 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5250 @*/ 5251 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5252 { 5253 DMLabel label; 5254 PetscInt dim, depth = -1, eStart = -1, Nf; 5255 PetscBool vertexchart; 5256 5257 PetscFunctionBegin; 5258 PetscCall(DMGetDimension(dm, &dim)); 5259 if (dim < 1) PetscFunctionReturn(0); 5260 if (point < 0) { 5261 PetscInt sStart,sEnd; 5262 5263 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5264 point = sEnd-sStart ? sStart : point; 5265 } 5266 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5267 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5268 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5269 if (depth == 1) {eStart = point;} 5270 else if (depth == dim) { 5271 const PetscInt *cone; 5272 5273 PetscCall(DMPlexGetCone(dm, point, &cone)); 5274 if (dim == 2) eStart = cone[0]; 5275 else if (dim == 3) { 5276 const PetscInt *cone2; 5277 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5278 eStart = cone2[0]; 5279 } 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); 5280 } 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); 5281 { /* Determine whether the chart covers all points or just vertices. */ 5282 PetscInt pStart,pEnd,cStart,cEnd; 5283 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5284 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5285 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5286 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5287 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5288 } 5289 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5290 for (PetscInt d=1; d<=dim; d++) { 5291 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5292 PetscInt *perm; 5293 5294 for (f = 0; f < Nf; ++f) { 5295 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5296 size += PetscPowInt(k+1, d)*Nc; 5297 } 5298 PetscCall(PetscMalloc1(size, &perm)); 5299 for (f = 0; f < Nf; ++f) { 5300 switch (d) { 5301 case 1: 5302 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5303 /* 5304 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5305 We want [ vtx0; edge of length k-1; vtx1 ] 5306 */ 5307 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5308 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5309 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5310 foffset = offset; 5311 break; 5312 case 2: 5313 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5314 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5315 /* The SEM order is 5316 5317 v_lb, {e_b}, v_rb, 5318 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5319 v_lt, reverse {e_t}, v_rt 5320 */ 5321 { 5322 const PetscInt of = 0; 5323 const PetscInt oeb = of + PetscSqr(k-1); 5324 const PetscInt oer = oeb + (k-1); 5325 const PetscInt oet = oer + (k-1); 5326 const PetscInt oel = oet + (k-1); 5327 const PetscInt ovlb = oel + (k-1); 5328 const PetscInt ovrb = ovlb + 1; 5329 const PetscInt ovrt = ovrb + 1; 5330 const PetscInt ovlt = ovrt + 1; 5331 PetscInt o; 5332 5333 /* bottom */ 5334 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5335 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5336 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5337 /* middle */ 5338 for (i = 0; i < k-1; ++i) { 5339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5340 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; 5341 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5342 } 5343 /* top */ 5344 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5345 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5346 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5347 foffset = offset; 5348 } 5349 break; 5350 case 3: 5351 /* The original hex closure is 5352 5353 {c, 5354 f_b, f_t, f_f, f_b, f_r, f_l, 5355 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5356 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5357 */ 5358 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5359 /* The SEM order is 5360 Bottom Slice 5361 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5362 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5363 v_blb, {e_bb}, v_brb, 5364 5365 Middle Slice (j) 5366 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5367 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5368 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5369 5370 Top Slice 5371 v_tlf, {e_tf}, v_trf, 5372 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5373 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5374 */ 5375 { 5376 const PetscInt oc = 0; 5377 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5378 const PetscInt oft = ofb + PetscSqr(k-1); 5379 const PetscInt off = oft + PetscSqr(k-1); 5380 const PetscInt ofk = off + PetscSqr(k-1); 5381 const PetscInt ofr = ofk + PetscSqr(k-1); 5382 const PetscInt ofl = ofr + PetscSqr(k-1); 5383 const PetscInt oebl = ofl + PetscSqr(k-1); 5384 const PetscInt oebb = oebl + (k-1); 5385 const PetscInt oebr = oebb + (k-1); 5386 const PetscInt oebf = oebr + (k-1); 5387 const PetscInt oetf = oebf + (k-1); 5388 const PetscInt oetr = oetf + (k-1); 5389 const PetscInt oetb = oetr + (k-1); 5390 const PetscInt oetl = oetb + (k-1); 5391 const PetscInt oerf = oetl + (k-1); 5392 const PetscInt oelf = oerf + (k-1); 5393 const PetscInt oelb = oelf + (k-1); 5394 const PetscInt oerb = oelb + (k-1); 5395 const PetscInt ovblf = oerb + (k-1); 5396 const PetscInt ovblb = ovblf + 1; 5397 const PetscInt ovbrb = ovblb + 1; 5398 const PetscInt ovbrf = ovbrb + 1; 5399 const PetscInt ovtlf = ovbrf + 1; 5400 const PetscInt ovtrf = ovtlf + 1; 5401 const PetscInt ovtrb = ovtrf + 1; 5402 const PetscInt ovtlb = ovtrb + 1; 5403 PetscInt o, n; 5404 5405 /* Bottom Slice */ 5406 /* bottom */ 5407 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5408 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5409 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5410 /* middle */ 5411 for (i = 0; i < k-1; ++i) { 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5413 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;} 5414 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5415 } 5416 /* top */ 5417 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5418 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5419 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5420 5421 /* Middle Slice */ 5422 for (j = 0; j < k-1; ++j) { 5423 /* bottom */ 5424 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5425 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; 5426 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5427 /* middle */ 5428 for (i = 0; i < k-1; ++i) { 5429 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5430 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; 5431 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5432 } 5433 /* top */ 5434 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5435 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; 5436 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5437 } 5438 5439 /* Top Slice */ 5440 /* bottom */ 5441 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5442 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5443 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5444 /* middle */ 5445 for (i = 0; i < k-1; ++i) { 5446 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5447 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5448 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5449 } 5450 /* top */ 5451 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5452 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5453 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5454 5455 foffset = offset; 5456 } 5457 break; 5458 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5459 } 5460 } 5461 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5462 /* Check permutation */ 5463 { 5464 PetscInt *check; 5465 5466 PetscCall(PetscMalloc1(size, &check)); 5467 for (i = 0; i < size; ++i) { 5468 check[i] = -1; 5469 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5470 } 5471 for (i = 0; i < size; ++i) check[perm[i]] = i; 5472 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5473 PetscCall(PetscFree(check)); 5474 } 5475 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5476 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5477 PetscInt *loc_perm; 5478 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5479 for (PetscInt i=0; i<size; i++) { 5480 loc_perm[i] = perm[i]; 5481 loc_perm[size+i] = size + perm[i]; 5482 } 5483 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5484 } 5485 } 5486 PetscFunctionReturn(0); 5487 } 5488 5489 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5490 { 5491 PetscDS prob; 5492 PetscInt depth, Nf, h; 5493 DMLabel label; 5494 5495 PetscFunctionBeginHot; 5496 PetscCall(DMGetDS(dm, &prob)); 5497 Nf = prob->Nf; 5498 label = dm->depthLabel; 5499 *dspace = NULL; 5500 if (field < Nf) { 5501 PetscObject disc = prob->disc[field]; 5502 5503 if (disc->classid == PETSCFE_CLASSID) { 5504 PetscDualSpace dsp; 5505 5506 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5507 PetscCall(DMLabelGetNumValues(label,&depth)); 5508 PetscCall(DMLabelGetValue(label,point,&h)); 5509 h = depth - 1 - h; 5510 if (h) { 5511 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5512 } else { 5513 *dspace = dsp; 5514 } 5515 } 5516 } 5517 PetscFunctionReturn(0); 5518 } 5519 5520 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5521 { 5522 PetscScalar *array, *vArray; 5523 const PetscInt *cone, *coneO; 5524 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5525 5526 PetscFunctionBeginHot; 5527 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5528 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5529 PetscCall(DMPlexGetCone(dm, point, &cone)); 5530 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5531 if (!values || !*values) { 5532 if ((point >= pStart) && (point < pEnd)) { 5533 PetscInt dof; 5534 5535 PetscCall(PetscSectionGetDof(section, point, &dof)); 5536 size += dof; 5537 } 5538 for (p = 0; p < numPoints; ++p) { 5539 const PetscInt cp = cone[p]; 5540 PetscInt dof; 5541 5542 if ((cp < pStart) || (cp >= pEnd)) continue; 5543 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5544 size += dof; 5545 } 5546 if (!values) { 5547 if (csize) *csize = size; 5548 PetscFunctionReturn(0); 5549 } 5550 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5551 } else { 5552 array = *values; 5553 } 5554 size = 0; 5555 PetscCall(VecGetArray(v, &vArray)); 5556 if ((point >= pStart) && (point < pEnd)) { 5557 PetscInt dof, off, d; 5558 PetscScalar *varr; 5559 5560 PetscCall(PetscSectionGetDof(section, point, &dof)); 5561 PetscCall(PetscSectionGetOffset(section, point, &off)); 5562 varr = &vArray[off]; 5563 for (d = 0; d < dof; ++d, ++offset) { 5564 array[offset] = varr[d]; 5565 } 5566 size += dof; 5567 } 5568 for (p = 0; p < numPoints; ++p) { 5569 const PetscInt cp = cone[p]; 5570 PetscInt o = coneO[p]; 5571 PetscInt dof, off, d; 5572 PetscScalar *varr; 5573 5574 if ((cp < pStart) || (cp >= pEnd)) continue; 5575 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5576 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5577 varr = &vArray[off]; 5578 if (o >= 0) { 5579 for (d = 0; d < dof; ++d, ++offset) { 5580 array[offset] = varr[d]; 5581 } 5582 } else { 5583 for (d = dof-1; d >= 0; --d, ++offset) { 5584 array[offset] = varr[d]; 5585 } 5586 } 5587 size += dof; 5588 } 5589 PetscCall(VecRestoreArray(v, &vArray)); 5590 if (!*values) { 5591 if (csize) *csize = size; 5592 *values = array; 5593 } else { 5594 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5595 *csize = size; 5596 } 5597 PetscFunctionReturn(0); 5598 } 5599 5600 /* Compress out points not in the section */ 5601 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5602 { 5603 const PetscInt np = *numPoints; 5604 PetscInt pStart, pEnd, p, q; 5605 5606 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5607 for (p = 0, q = 0; p < np; ++p) { 5608 const PetscInt r = points[p*2]; 5609 if ((r >= pStart) && (r < pEnd)) { 5610 points[q*2] = r; 5611 points[q*2+1] = points[p*2+1]; 5612 ++q; 5613 } 5614 } 5615 *numPoints = q; 5616 return 0; 5617 } 5618 5619 /* Compressed closure does not apply closure permutation */ 5620 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5621 { 5622 const PetscInt *cla = NULL; 5623 PetscInt np, *pts = NULL; 5624 5625 PetscFunctionBeginHot; 5626 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5627 if (*clPoints) { 5628 PetscInt dof, off; 5629 5630 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5631 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5632 PetscCall(ISGetIndices(*clPoints, &cla)); 5633 np = dof/2; 5634 pts = (PetscInt *) &cla[off]; 5635 } else { 5636 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5637 PetscCall(CompressPoints_Private(section, &np, pts)); 5638 } 5639 *numPoints = np; 5640 *points = pts; 5641 *clp = cla; 5642 PetscFunctionReturn(0); 5643 } 5644 5645 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5646 { 5647 PetscFunctionBeginHot; 5648 if (!*clPoints) { 5649 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5650 } else { 5651 PetscCall(ISRestoreIndices(*clPoints, clp)); 5652 } 5653 *numPoints = 0; 5654 *points = NULL; 5655 *clSec = NULL; 5656 *clPoints = NULL; 5657 *clp = NULL; 5658 PetscFunctionReturn(0); 5659 } 5660 5661 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5662 { 5663 PetscInt offset = 0, p; 5664 const PetscInt **perms = NULL; 5665 const PetscScalar **flips = NULL; 5666 5667 PetscFunctionBeginHot; 5668 *size = 0; 5669 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5670 for (p = 0; p < numPoints; p++) { 5671 const PetscInt point = points[2*p]; 5672 const PetscInt *perm = perms ? perms[p] : NULL; 5673 const PetscScalar *flip = flips ? flips[p] : NULL; 5674 PetscInt dof, off, d; 5675 const PetscScalar *varr; 5676 5677 PetscCall(PetscSectionGetDof(section, point, &dof)); 5678 PetscCall(PetscSectionGetOffset(section, point, &off)); 5679 varr = &vArray[off]; 5680 if (clperm) { 5681 if (perm) { 5682 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5683 } else { 5684 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5685 } 5686 if (flip) { 5687 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5688 } 5689 } else { 5690 if (perm) { 5691 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5692 } else { 5693 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5694 } 5695 if (flip) { 5696 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5697 } 5698 } 5699 offset += dof; 5700 } 5701 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5702 *size = offset; 5703 PetscFunctionReturn(0); 5704 } 5705 5706 static inline PetscErrorCode DMPlexVecGetClosure_Fields_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5707 { 5708 PetscInt offset = 0, f; 5709 5710 PetscFunctionBeginHot; 5711 *size = 0; 5712 for (f = 0; f < numFields; ++f) { 5713 PetscInt p; 5714 const PetscInt **perms = NULL; 5715 const PetscScalar **flips = NULL; 5716 5717 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5718 for (p = 0; p < numPoints; p++) { 5719 const PetscInt point = points[2*p]; 5720 PetscInt fdof, foff, b; 5721 const PetscScalar *varr; 5722 const PetscInt *perm = perms ? perms[p] : NULL; 5723 const PetscScalar *flip = flips ? flips[p] : NULL; 5724 5725 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5726 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5727 varr = &vArray[foff]; 5728 if (clperm) { 5729 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5730 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5731 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5732 } else { 5733 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5734 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5735 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5736 } 5737 offset += fdof; 5738 } 5739 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5740 } 5741 *size = offset; 5742 PetscFunctionReturn(0); 5743 } 5744 5745 /*@C 5746 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5747 5748 Not collective 5749 5750 Input Parameters: 5751 + dm - The DM 5752 . section - The section describing the layout in v, or NULL to use the default section 5753 . v - The local vector 5754 - point - The point in the DM 5755 5756 Input/Output Parameters: 5757 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5758 - values - An array to use for the values, or NULL to have it allocated automatically; 5759 if the user provided NULL, it is a borrowed array and should not be freed 5760 5761 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5762 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5763 $ assembly function, and a user may already have allocated storage for this operation. 5764 $ 5765 $ A typical use could be 5766 $ 5767 $ values = NULL; 5768 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5769 $ for (cl = 0; cl < clSize; ++cl) { 5770 $ <Compute on closure> 5771 $ } 5772 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5773 $ 5774 $ or 5775 $ 5776 $ PetscMalloc1(clMaxSize, &values); 5777 $ for (p = pStart; p < pEnd; ++p) { 5778 $ clSize = clMaxSize; 5779 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5780 $ for (cl = 0; cl < clSize; ++cl) { 5781 $ <Compute on closure> 5782 $ } 5783 $ } 5784 $ PetscFree(values); 5785 5786 Fortran Notes: 5787 Since it returns an array, this routine is only available in Fortran 90, and you must 5788 include petsc.h90 in your code. 5789 5790 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5791 5792 Level: intermediate 5793 5794 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5795 @*/ 5796 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5797 { 5798 PetscSection clSection; 5799 IS clPoints; 5800 PetscInt *points = NULL; 5801 const PetscInt *clp, *perm; 5802 PetscInt depth, numFields, numPoints, asize; 5803 5804 PetscFunctionBeginHot; 5805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5806 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5807 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5808 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5809 PetscCall(DMPlexGetDepth(dm, &depth)); 5810 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5811 if (depth == 1 && numFields < 2) { 5812 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5813 PetscFunctionReturn(0); 5814 } 5815 /* Get points */ 5816 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5817 /* Get sizes */ 5818 asize = 0; 5819 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5820 PetscInt dof; 5821 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5822 asize += dof; 5823 } 5824 if (values) { 5825 const PetscScalar *vArray; 5826 PetscInt size; 5827 5828 if (*values) { 5829 PetscCheck(*csize >= asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 5830 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5831 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5832 PetscCall(VecGetArrayRead(v, &vArray)); 5833 /* Get values */ 5834 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5835 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5836 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5837 /* Cleanup array */ 5838 PetscCall(VecRestoreArrayRead(v, &vArray)); 5839 } 5840 if (csize) *csize = asize; 5841 /* Cleanup points */ 5842 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5843 PetscFunctionReturn(0); 5844 } 5845 5846 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5847 { 5848 DMLabel depthLabel; 5849 PetscSection clSection; 5850 IS clPoints; 5851 PetscScalar *array; 5852 const PetscScalar *vArray; 5853 PetscInt *points = NULL; 5854 const PetscInt *clp, *perm = NULL; 5855 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5856 5857 PetscFunctionBeginHot; 5858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5859 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5860 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5861 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5862 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5863 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5864 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5865 if (mdepth == 1 && numFields < 2) { 5866 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5867 PetscFunctionReturn(0); 5868 } 5869 /* Get points */ 5870 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5871 for (clsize=0,p=0; p<Np; p++) { 5872 PetscInt dof; 5873 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5874 clsize += dof; 5875 } 5876 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5877 /* Filter points */ 5878 for (p = 0; p < numPoints*2; p += 2) { 5879 PetscInt dep; 5880 5881 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5882 if (dep != depth) continue; 5883 points[Np*2+0] = points[p]; 5884 points[Np*2+1] = points[p+1]; 5885 ++Np; 5886 } 5887 /* Get array */ 5888 if (!values || !*values) { 5889 PetscInt asize = 0, dof; 5890 5891 for (p = 0; p < Np*2; p += 2) { 5892 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5893 asize += dof; 5894 } 5895 if (!values) { 5896 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5897 if (csize) *csize = asize; 5898 PetscFunctionReturn(0); 5899 } 5900 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5901 } else { 5902 array = *values; 5903 } 5904 PetscCall(VecGetArrayRead(v, &vArray)); 5905 /* Get values */ 5906 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5907 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5908 /* Cleanup points */ 5909 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5910 /* Cleanup array */ 5911 PetscCall(VecRestoreArrayRead(v, &vArray)); 5912 if (!*values) { 5913 if (csize) *csize = size; 5914 *values = array; 5915 } else { 5916 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5917 *csize = size; 5918 } 5919 PetscFunctionReturn(0); 5920 } 5921 5922 /*@C 5923 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5924 5925 Not collective 5926 5927 Input Parameters: 5928 + dm - The DM 5929 . section - The section describing the layout in v, or NULL to use the default section 5930 . v - The local vector 5931 . point - The point in the DM 5932 . csize - The number of values in the closure, or NULL 5933 - values - The array of values, which is a borrowed array and should not be freed 5934 5935 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5936 5937 Fortran Notes: 5938 Since it returns an array, this routine is only available in Fortran 90, and you must 5939 include petsc.h90 in your code. 5940 5941 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5942 5943 Level: intermediate 5944 5945 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5946 @*/ 5947 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5948 { 5949 PetscInt size = 0; 5950 5951 PetscFunctionBegin; 5952 /* Should work without recalculating size */ 5953 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5954 *values = NULL; 5955 PetscFunctionReturn(0); 5956 } 5957 5958 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5959 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5960 5961 static inline PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 5962 { 5963 PetscInt cdof; /* The number of constraints on this point */ 5964 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5965 PetscScalar *a; 5966 PetscInt off, cind = 0, k; 5967 5968 PetscFunctionBegin; 5969 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5970 PetscCall(PetscSectionGetOffset(section, point, &off)); 5971 a = &array[off]; 5972 if (!cdof || setBC) { 5973 if (clperm) { 5974 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5975 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5976 } else { 5977 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5978 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5979 } 5980 } else { 5981 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5982 if (clperm) { 5983 if (perm) {for (k = 0; k < dof; ++k) { 5984 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5985 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5986 } 5987 } else { 5988 for (k = 0; k < dof; ++k) { 5989 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5990 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5991 } 5992 } 5993 } else { 5994 if (perm) { 5995 for (k = 0; k < dof; ++k) { 5996 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5997 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5998 } 5999 } else { 6000 for (k = 0; k < dof; ++k) { 6001 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6002 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6003 } 6004 } 6005 } 6006 } 6007 PetscFunctionReturn(0); 6008 } 6009 6010 static inline PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar flip[], const PetscInt clperm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 6011 { 6012 PetscInt cdof; /* The number of constraints on this point */ 6013 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6014 PetscScalar *a; 6015 PetscInt off, cind = 0, k; 6016 6017 PetscFunctionBegin; 6018 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6019 PetscCall(PetscSectionGetOffset(section, point, &off)); 6020 a = &array[off]; 6021 if (cdof) { 6022 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6023 if (clperm) { 6024 if (perm) { 6025 for (k = 0; k < dof; ++k) { 6026 if ((cind < cdof) && (k == cdofs[cind])) { 6027 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6028 cind++; 6029 } 6030 } 6031 } else { 6032 for (k = 0; k < dof; ++k) { 6033 if ((cind < cdof) && (k == cdofs[cind])) { 6034 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6035 cind++; 6036 } 6037 } 6038 } 6039 } else { 6040 if (perm) { 6041 for (k = 0; k < dof; ++k) { 6042 if ((cind < cdof) && (k == cdofs[cind])) { 6043 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6044 cind++; 6045 } 6046 } 6047 } else { 6048 for (k = 0; k < dof; ++k) { 6049 if ((cind < cdof) && (k == cdofs[cind])) { 6050 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6051 cind++; 6052 } 6053 } 6054 } 6055 } 6056 } 6057 PetscFunctionReturn(0); 6058 } 6059 6060 static inline PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, const PetscInt *perm, const PetscScalar *flip, PetscInt f, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6061 { 6062 PetscScalar *a; 6063 PetscInt fdof, foff, fcdof, foffset = *offset; 6064 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6065 PetscInt cind = 0, b; 6066 6067 PetscFunctionBegin; 6068 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6069 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6070 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6071 a = &array[foff]; 6072 if (!fcdof || setBC) { 6073 if (clperm) { 6074 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6075 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6076 } else { 6077 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6078 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6079 } 6080 } else { 6081 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6082 if (clperm) { 6083 if (perm) { 6084 for (b = 0; b < fdof; b++) { 6085 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6086 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6087 } 6088 } else { 6089 for (b = 0; b < fdof; b++) { 6090 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6091 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6092 } 6093 } 6094 } else { 6095 if (perm) { 6096 for (b = 0; b < fdof; b++) { 6097 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6098 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6099 } 6100 } else { 6101 for (b = 0; b < fdof; b++) { 6102 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6103 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6104 } 6105 } 6106 } 6107 } 6108 *offset += fdof; 6109 PetscFunctionReturn(0); 6110 } 6111 6112 static inline PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, const PetscInt perm[], const PetscScalar flip[], PetscInt f, PetscInt Ncc, const PetscInt comps[], void (*fuse)(PetscScalar*, PetscScalar), const PetscInt clperm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 6113 { 6114 PetscScalar *a; 6115 PetscInt fdof, foff, fcdof, foffset = *offset; 6116 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6117 PetscInt Nc, cind = 0, ncind = 0, b; 6118 PetscBool ncSet, fcSet; 6119 6120 PetscFunctionBegin; 6121 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6122 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6123 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6124 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6125 a = &array[foff]; 6126 if (fcdof) { 6127 /* We just override fcdof and fcdofs with Ncc and comps */ 6128 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6129 if (clperm) { 6130 if (perm) { 6131 if (comps) { 6132 for (b = 0; b < fdof; b++) { 6133 ncSet = fcSet = PETSC_FALSE; 6134 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6135 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6136 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6137 } 6138 } else { 6139 for (b = 0; b < fdof; b++) { 6140 if ((cind < fcdof) && (b == fcdofs[cind])) { 6141 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6142 ++cind; 6143 } 6144 } 6145 } 6146 } else { 6147 if (comps) { 6148 for (b = 0; b < fdof; b++) { 6149 ncSet = fcSet = PETSC_FALSE; 6150 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6151 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6152 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6153 } 6154 } else { 6155 for (b = 0; b < fdof; b++) { 6156 if ((cind < fcdof) && (b == fcdofs[cind])) { 6157 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6158 ++cind; 6159 } 6160 } 6161 } 6162 } 6163 } else { 6164 if (perm) { 6165 if (comps) { 6166 for (b = 0; b < fdof; b++) { 6167 ncSet = fcSet = PETSC_FALSE; 6168 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6169 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6170 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6171 } 6172 } else { 6173 for (b = 0; b < fdof; b++) { 6174 if ((cind < fcdof) && (b == fcdofs[cind])) { 6175 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6176 ++cind; 6177 } 6178 } 6179 } 6180 } else { 6181 if (comps) { 6182 for (b = 0; b < fdof; b++) { 6183 ncSet = fcSet = PETSC_FALSE; 6184 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6185 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6186 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6187 } 6188 } else { 6189 for (b = 0; b < fdof; b++) { 6190 if ((cind < fcdof) && (b == fcdofs[cind])) { 6191 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6192 ++cind; 6193 } 6194 } 6195 } 6196 } 6197 } 6198 } 6199 *offset += fdof; 6200 PetscFunctionReturn(0); 6201 } 6202 6203 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6204 { 6205 PetscScalar *array; 6206 const PetscInt *cone, *coneO; 6207 PetscInt pStart, pEnd, p, numPoints, off, dof; 6208 6209 PetscFunctionBeginHot; 6210 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6211 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6212 PetscCall(DMPlexGetCone(dm, point, &cone)); 6213 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6214 PetscCall(VecGetArray(v, &array)); 6215 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6216 const PetscInt cp = !p ? point : cone[p-1]; 6217 const PetscInt o = !p ? 0 : coneO[p-1]; 6218 6219 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6220 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6221 /* ADD_VALUES */ 6222 { 6223 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6224 PetscScalar *a; 6225 PetscInt cdof, coff, cind = 0, k; 6226 6227 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6228 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6229 a = &array[coff]; 6230 if (!cdof) { 6231 if (o >= 0) { 6232 for (k = 0; k < dof; ++k) { 6233 a[k] += values[off+k]; 6234 } 6235 } else { 6236 for (k = 0; k < dof; ++k) { 6237 a[k] += values[off+dof-k-1]; 6238 } 6239 } 6240 } else { 6241 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6242 if (o >= 0) { 6243 for (k = 0; k < dof; ++k) { 6244 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6245 a[k] += values[off+k]; 6246 } 6247 } else { 6248 for (k = 0; k < dof; ++k) { 6249 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6250 a[k] += values[off+dof-k-1]; 6251 } 6252 } 6253 } 6254 } 6255 } 6256 PetscCall(VecRestoreArray(v, &array)); 6257 PetscFunctionReturn(0); 6258 } 6259 6260 /*@C 6261 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6262 6263 Not collective 6264 6265 Input Parameters: 6266 + dm - The DM 6267 . section - The section describing the layout in v, or NULL to use the default section 6268 . v - The local vector 6269 . point - The point in the DM 6270 . values - The array of values 6271 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6272 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6273 6274 Fortran Notes: 6275 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6276 6277 Level: intermediate 6278 6279 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6280 @*/ 6281 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6282 { 6283 PetscSection clSection; 6284 IS clPoints; 6285 PetscScalar *array; 6286 PetscInt *points = NULL; 6287 const PetscInt *clp, *clperm = NULL; 6288 PetscInt depth, numFields, numPoints, p, clsize; 6289 6290 PetscFunctionBeginHot; 6291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6292 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6293 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6294 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6295 PetscCall(DMPlexGetDepth(dm, &depth)); 6296 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6297 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6298 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6299 PetscFunctionReturn(0); 6300 } 6301 /* Get points */ 6302 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6303 for (clsize=0,p=0; p<numPoints; p++) { 6304 PetscInt dof; 6305 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6306 clsize += dof; 6307 } 6308 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6309 /* Get array */ 6310 PetscCall(VecGetArray(v, &array)); 6311 /* Get values */ 6312 if (numFields > 0) { 6313 PetscInt offset = 0, f; 6314 for (f = 0; f < numFields; ++f) { 6315 const PetscInt **perms = NULL; 6316 const PetscScalar **flips = NULL; 6317 6318 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6319 switch (mode) { 6320 case INSERT_VALUES: 6321 for (p = 0; p < numPoints; p++) { 6322 const PetscInt point = points[2*p]; 6323 const PetscInt *perm = perms ? perms[p] : NULL; 6324 const PetscScalar *flip = flips ? flips[p] : NULL; 6325 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6326 } break; 6327 case INSERT_ALL_VALUES: 6328 for (p = 0; p < numPoints; p++) { 6329 const PetscInt point = points[2*p]; 6330 const PetscInt *perm = perms ? perms[p] : NULL; 6331 const PetscScalar *flip = flips ? flips[p] : NULL; 6332 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6333 } break; 6334 case INSERT_BC_VALUES: 6335 for (p = 0; p < numPoints; p++) { 6336 const PetscInt point = points[2*p]; 6337 const PetscInt *perm = perms ? perms[p] : NULL; 6338 const PetscScalar *flip = flips ? flips[p] : NULL; 6339 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6340 } break; 6341 case ADD_VALUES: 6342 for (p = 0; p < numPoints; p++) { 6343 const PetscInt point = points[2*p]; 6344 const PetscInt *perm = perms ? perms[p] : NULL; 6345 const PetscScalar *flip = flips ? flips[p] : NULL; 6346 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6347 } break; 6348 case ADD_ALL_VALUES: 6349 for (p = 0; p < numPoints; p++) { 6350 const PetscInt point = points[2*p]; 6351 const PetscInt *perm = perms ? perms[p] : NULL; 6352 const PetscScalar *flip = flips ? flips[p] : NULL; 6353 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6354 } break; 6355 case ADD_BC_VALUES: 6356 for (p = 0; p < numPoints; p++) { 6357 const PetscInt point = points[2*p]; 6358 const PetscInt *perm = perms ? perms[p] : NULL; 6359 const PetscScalar *flip = flips ? flips[p] : NULL; 6360 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6361 } break; 6362 default: 6363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6364 } 6365 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6366 } 6367 } else { 6368 PetscInt dof, off; 6369 const PetscInt **perms = NULL; 6370 const PetscScalar **flips = NULL; 6371 6372 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6373 switch (mode) { 6374 case INSERT_VALUES: 6375 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6376 const PetscInt point = points[2*p]; 6377 const PetscInt *perm = perms ? perms[p] : NULL; 6378 const PetscScalar *flip = flips ? flips[p] : NULL; 6379 PetscCall(PetscSectionGetDof(section, point, &dof)); 6380 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6381 } break; 6382 case INSERT_ALL_VALUES: 6383 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6384 const PetscInt point = points[2*p]; 6385 const PetscInt *perm = perms ? perms[p] : NULL; 6386 const PetscScalar *flip = flips ? flips[p] : NULL; 6387 PetscCall(PetscSectionGetDof(section, point, &dof)); 6388 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6389 } break; 6390 case INSERT_BC_VALUES: 6391 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6392 const PetscInt point = points[2*p]; 6393 const PetscInt *perm = perms ? perms[p] : NULL; 6394 const PetscScalar *flip = flips ? flips[p] : NULL; 6395 PetscCall(PetscSectionGetDof(section, point, &dof)); 6396 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6397 } break; 6398 case ADD_VALUES: 6399 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6400 const PetscInt point = points[2*p]; 6401 const PetscInt *perm = perms ? perms[p] : NULL; 6402 const PetscScalar *flip = flips ? flips[p] : NULL; 6403 PetscCall(PetscSectionGetDof(section, point, &dof)); 6404 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6405 } break; 6406 case ADD_ALL_VALUES: 6407 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6408 const PetscInt point = points[2*p]; 6409 const PetscInt *perm = perms ? perms[p] : NULL; 6410 const PetscScalar *flip = flips ? flips[p] : NULL; 6411 PetscCall(PetscSectionGetDof(section, point, &dof)); 6412 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6413 } break; 6414 case ADD_BC_VALUES: 6415 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6416 const PetscInt point = points[2*p]; 6417 const PetscInt *perm = perms ? perms[p] : NULL; 6418 const PetscScalar *flip = flips ? flips[p] : NULL; 6419 PetscCall(PetscSectionGetDof(section, point, &dof)); 6420 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6421 } break; 6422 default: 6423 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6424 } 6425 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6426 } 6427 /* Cleanup points */ 6428 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6429 /* Cleanup array */ 6430 PetscCall(VecRestoreArray(v, &array)); 6431 PetscFunctionReturn(0); 6432 } 6433 6434 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6435 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6436 { 6437 PetscFunctionBegin; 6438 if (label) { 6439 PetscInt val, fdof; 6440 6441 /* There is a problem with this: 6442 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6443 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6444 Thus I am only going to check val != -1, not val != labelId 6445 */ 6446 PetscCall(DMLabelGetValue(label, point, &val)); 6447 if (val < 0) { 6448 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6449 *offset += fdof; 6450 PetscFunctionReturn(1); 6451 } 6452 } 6453 PetscFunctionReturn(0); 6454 } 6455 6456 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6457 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt labelId, const PetscScalar values[], InsertMode mode) 6458 { 6459 PetscSection clSection; 6460 IS clPoints; 6461 PetscScalar *array; 6462 PetscInt *points = NULL; 6463 const PetscInt *clp; 6464 PetscInt numFields, numPoints, p; 6465 PetscInt offset = 0, f; 6466 6467 PetscFunctionBeginHot; 6468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6469 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6470 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6471 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6472 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6473 /* Get points */ 6474 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6475 /* Get array */ 6476 PetscCall(VecGetArray(v, &array)); 6477 /* Get values */ 6478 for (f = 0; f < numFields; ++f) { 6479 const PetscInt **perms = NULL; 6480 const PetscScalar **flips = NULL; 6481 6482 if (!fieldActive[f]) { 6483 for (p = 0; p < numPoints*2; p += 2) { 6484 PetscInt fdof; 6485 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6486 offset += fdof; 6487 } 6488 continue; 6489 } 6490 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6491 switch (mode) { 6492 case INSERT_VALUES: 6493 for (p = 0; p < numPoints; p++) { 6494 const PetscInt point = points[2*p]; 6495 const PetscInt *perm = perms ? perms[p] : NULL; 6496 const PetscScalar *flip = flips ? flips[p] : NULL; 6497 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6498 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6499 } break; 6500 case INSERT_ALL_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2*p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6506 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6507 } break; 6508 case INSERT_BC_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2*p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6514 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6515 } break; 6516 case ADD_VALUES: 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2*p]; 6519 const PetscInt *perm = perms ? perms[p] : NULL; 6520 const PetscScalar *flip = flips ? flips[p] : NULL; 6521 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6522 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6523 } break; 6524 case ADD_ALL_VALUES: 6525 for (p = 0; p < numPoints; p++) { 6526 const PetscInt point = points[2*p]; 6527 const PetscInt *perm = perms ? perms[p] : NULL; 6528 const PetscScalar *flip = flips ? flips[p] : NULL; 6529 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6530 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6531 } break; 6532 default: 6533 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6534 } 6535 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6536 } 6537 /* Cleanup points */ 6538 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6539 /* Cleanup array */ 6540 PetscCall(VecRestoreArray(v, &array)); 6541 PetscFunctionReturn(0); 6542 } 6543 6544 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6545 { 6546 PetscMPIInt rank; 6547 PetscInt i, j; 6548 6549 PetscFunctionBegin; 6550 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6551 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6552 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6553 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6554 numCIndices = numCIndices ? numCIndices : numRIndices; 6555 if (!values) PetscFunctionReturn(0); 6556 for (i = 0; i < numRIndices; i++) { 6557 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6558 for (j = 0; j < numCIndices; j++) { 6559 #if defined(PETSC_USE_COMPLEX) 6560 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6561 #else 6562 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6563 #endif 6564 } 6565 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6566 } 6567 PetscFunctionReturn(0); 6568 } 6569 6570 /* 6571 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6572 6573 Input Parameters: 6574 + section - The section for this data layout 6575 . islocal - Is the section (and thus indices being requested) local or global? 6576 . point - The point contributing dofs with these indices 6577 . off - The global offset of this point 6578 . loff - The local offset of each field 6579 . setBC - The flag determining whether to include indices of boundary values 6580 . perm - A permutation of the dofs on this point, or NULL 6581 - indperm - A permutation of the entire indices array, or NULL 6582 6583 Output Parameter: 6584 . indices - Indices for dofs on this point 6585 6586 Level: developer 6587 6588 Note: The indices could be local or global, depending on the value of 'off'. 6589 */ 6590 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6591 { 6592 PetscInt dof; /* The number of unknowns on this point */ 6593 PetscInt cdof; /* The number of constraints on this point */ 6594 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6595 PetscInt cind = 0, k; 6596 6597 PetscFunctionBegin; 6598 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6599 PetscCall(PetscSectionGetDof(section, point, &dof)); 6600 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6601 if (!cdof || setBC) { 6602 for (k = 0; k < dof; ++k) { 6603 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6604 const PetscInt ind = indperm ? indperm[preind] : preind; 6605 6606 indices[ind] = off + k; 6607 } 6608 } else { 6609 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6610 for (k = 0; k < dof; ++k) { 6611 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6612 const PetscInt ind = indperm ? indperm[preind] : preind; 6613 6614 if ((cind < cdof) && (k == cdofs[cind])) { 6615 /* Insert check for returning constrained indices */ 6616 indices[ind] = -(off+k+1); 6617 ++cind; 6618 } else { 6619 indices[ind] = off + k - (islocal ? 0 : cind); 6620 } 6621 } 6622 } 6623 *loff += dof; 6624 PetscFunctionReturn(0); 6625 } 6626 6627 /* 6628 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6629 6630 Input Parameters: 6631 + section - a section (global or local) 6632 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6633 . point - point within section 6634 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6635 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6636 . setBC - identify constrained (boundary condition) points via involution. 6637 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6638 . permsoff - offset 6639 - indperm - index permutation 6640 6641 Output Parameter: 6642 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6643 . indices - array to hold indices (as defined by section) of each dof associated with point 6644 6645 Notes: 6646 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6647 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6648 in the local vector. 6649 6650 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6651 significant). It is invalid to call with a global section and setBC=true. 6652 6653 Developer Note: 6654 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6655 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6656 offset could be obtained from the section instead of passing it explicitly as we do now. 6657 6658 Example: 6659 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6660 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6661 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6662 The global vector does not store constrained dofs, so when this function returns global indices, say {110, -112, 111}, the value of -112 is an arbitrary flag that should not be interpreted beyond its sign. 6663 6664 Level: developer 6665 */ 6666 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6667 { 6668 PetscInt numFields, foff, f; 6669 6670 PetscFunctionBegin; 6671 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6672 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6673 for (f = 0, foff = 0; f < numFields; ++f) { 6674 PetscInt fdof, cfdof; 6675 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6676 PetscInt cind = 0, b; 6677 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6678 6679 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6680 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6681 if (!cfdof || setBC) { 6682 for (b = 0; b < fdof; ++b) { 6683 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6684 const PetscInt ind = indperm ? indperm[preind] : preind; 6685 6686 indices[ind] = off+foff+b; 6687 } 6688 } else { 6689 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6690 for (b = 0; b < fdof; ++b) { 6691 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6692 const PetscInt ind = indperm ? indperm[preind] : preind; 6693 6694 if ((cind < cfdof) && (b == fcdofs[cind])) { 6695 indices[ind] = -(off+foff+b+1); 6696 ++cind; 6697 } else { 6698 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6699 } 6700 } 6701 } 6702 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6703 foffs[f] += fdof; 6704 } 6705 PetscFunctionReturn(0); 6706 } 6707 6708 /* 6709 This version believes the globalSection offsets for each field, rather than just the point offset 6710 6711 . foffs - The offset into 'indices' for each field, since it is segregated by field 6712 6713 Notes: 6714 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6715 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6716 */ 6717 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6718 { 6719 PetscInt numFields, foff, f; 6720 6721 PetscFunctionBegin; 6722 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6723 for (f = 0; f < numFields; ++f) { 6724 PetscInt fdof, cfdof; 6725 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6726 PetscInt cind = 0, b; 6727 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6728 6729 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6730 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6731 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6732 if (!cfdof) { 6733 for (b = 0; b < fdof; ++b) { 6734 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6735 const PetscInt ind = indperm ? indperm[preind] : preind; 6736 6737 indices[ind] = foff+b; 6738 } 6739 } else { 6740 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6741 for (b = 0; b < fdof; ++b) { 6742 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6743 const PetscInt ind = indperm ? indperm[preind] : preind; 6744 6745 if ((cind < cfdof) && (b == fcdofs[cind])) { 6746 indices[ind] = -(foff+b+1); 6747 ++cind; 6748 } else { 6749 indices[ind] = foff+b-cind; 6750 } 6751 } 6752 } 6753 foffs[f] += fdof; 6754 } 6755 PetscFunctionReturn(0); 6756 } 6757 6758 PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 6759 { 6760 Mat cMat; 6761 PetscSection aSec, cSec; 6762 IS aIS; 6763 PetscInt aStart = -1, aEnd = -1; 6764 const PetscInt *anchors; 6765 PetscInt numFields, f, p, q, newP = 0; 6766 PetscInt newNumPoints = 0, newNumIndices = 0; 6767 PetscInt *newPoints, *indices, *newIndices; 6768 PetscInt maxAnchor, maxDof; 6769 PetscInt newOffsets[32]; 6770 PetscInt *pointMatOffsets[32]; 6771 PetscInt *newPointOffsets[32]; 6772 PetscScalar *pointMat[32]; 6773 PetscScalar *newValues=NULL,*tmpValues; 6774 PetscBool anyConstrained = PETSC_FALSE; 6775 6776 PetscFunctionBegin; 6777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6778 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6779 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6780 6781 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6782 /* if there are point-to-point constraints */ 6783 if (aSec) { 6784 PetscCall(PetscArrayzero(newOffsets, 32)); 6785 PetscCall(ISGetIndices(aIS,&anchors)); 6786 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6787 /* figure out how many points are going to be in the new element matrix 6788 * (we allow double counting, because it's all just going to be summed 6789 * into the global matrix anyway) */ 6790 for (p = 0; p < 2*numPoints; p+=2) { 6791 PetscInt b = points[p]; 6792 PetscInt bDof = 0, bSecDof; 6793 6794 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6795 if (!bSecDof) { 6796 continue; 6797 } 6798 if (b >= aStart && b < aEnd) { 6799 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6800 } 6801 if (bDof) { 6802 /* this point is constrained */ 6803 /* it is going to be replaced by its anchors */ 6804 PetscInt bOff, q; 6805 6806 anyConstrained = PETSC_TRUE; 6807 newNumPoints += bDof; 6808 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6809 for (q = 0; q < bDof; q++) { 6810 PetscInt a = anchors[bOff + q]; 6811 PetscInt aDof; 6812 6813 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6814 newNumIndices += aDof; 6815 for (f = 0; f < numFields; ++f) { 6816 PetscInt fDof; 6817 6818 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6819 newOffsets[f+1] += fDof; 6820 } 6821 } 6822 } 6823 else { 6824 /* this point is not constrained */ 6825 newNumPoints++; 6826 newNumIndices += bSecDof; 6827 for (f = 0; f < numFields; ++f) { 6828 PetscInt fDof; 6829 6830 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6831 newOffsets[f+1] += fDof; 6832 } 6833 } 6834 } 6835 } 6836 if (!anyConstrained) { 6837 if (outNumPoints) *outNumPoints = 0; 6838 if (outNumIndices) *outNumIndices = 0; 6839 if (outPoints) *outPoints = NULL; 6840 if (outValues) *outValues = NULL; 6841 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6842 PetscFunctionReturn(0); 6843 } 6844 6845 if (outNumPoints) *outNumPoints = newNumPoints; 6846 if (outNumIndices) *outNumIndices = newNumIndices; 6847 6848 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6849 6850 if (!outPoints && !outValues) { 6851 if (offsets) { 6852 for (f = 0; f <= numFields; f++) { 6853 offsets[f] = newOffsets[f]; 6854 } 6855 } 6856 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6857 PetscFunctionReturn(0); 6858 } 6859 6860 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6861 6862 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6863 6864 /* workspaces */ 6865 if (numFields) { 6866 for (f = 0; f < numFields; f++) { 6867 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6868 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6869 } 6870 } 6871 else { 6872 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6873 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6874 } 6875 6876 /* get workspaces for the point-to-point matrices */ 6877 if (numFields) { 6878 PetscInt totalOffset, totalMatOffset; 6879 6880 for (p = 0; p < numPoints; p++) { 6881 PetscInt b = points[2*p]; 6882 PetscInt bDof = 0, bSecDof; 6883 6884 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6885 if (!bSecDof) { 6886 for (f = 0; f < numFields; f++) { 6887 newPointOffsets[f][p + 1] = 0; 6888 pointMatOffsets[f][p + 1] = 0; 6889 } 6890 continue; 6891 } 6892 if (b >= aStart && b < aEnd) { 6893 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6894 } 6895 if (bDof) { 6896 for (f = 0; f < numFields; f++) { 6897 PetscInt fDof, q, bOff, allFDof = 0; 6898 6899 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6900 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6901 for (q = 0; q < bDof; q++) { 6902 PetscInt a = anchors[bOff + q]; 6903 PetscInt aFDof; 6904 6905 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6906 allFDof += aFDof; 6907 } 6908 newPointOffsets[f][p+1] = allFDof; 6909 pointMatOffsets[f][p+1] = fDof * allFDof; 6910 } 6911 } 6912 else { 6913 for (f = 0; f < numFields; f++) { 6914 PetscInt fDof; 6915 6916 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6917 newPointOffsets[f][p+1] = fDof; 6918 pointMatOffsets[f][p+1] = 0; 6919 } 6920 } 6921 } 6922 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6923 newPointOffsets[f][0] = totalOffset; 6924 pointMatOffsets[f][0] = totalMatOffset; 6925 for (p = 0; p < numPoints; p++) { 6926 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6927 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6928 } 6929 totalOffset = newPointOffsets[f][numPoints]; 6930 totalMatOffset = pointMatOffsets[f][numPoints]; 6931 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6932 } 6933 } 6934 else { 6935 for (p = 0; p < numPoints; p++) { 6936 PetscInt b = points[2*p]; 6937 PetscInt bDof = 0, bSecDof; 6938 6939 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6940 if (!bSecDof) { 6941 newPointOffsets[0][p + 1] = 0; 6942 pointMatOffsets[0][p + 1] = 0; 6943 continue; 6944 } 6945 if (b >= aStart && b < aEnd) { 6946 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6947 } 6948 if (bDof) { 6949 PetscInt bOff, q, allDof = 0; 6950 6951 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6952 for (q = 0; q < bDof; q++) { 6953 PetscInt a = anchors[bOff + q], aDof; 6954 6955 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6956 allDof += aDof; 6957 } 6958 newPointOffsets[0][p+1] = allDof; 6959 pointMatOffsets[0][p+1] = bSecDof * allDof; 6960 } 6961 else { 6962 newPointOffsets[0][p+1] = bSecDof; 6963 pointMatOffsets[0][p+1] = 0; 6964 } 6965 } 6966 newPointOffsets[0][0] = 0; 6967 pointMatOffsets[0][0] = 0; 6968 for (p = 0; p < numPoints; p++) { 6969 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6970 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6971 } 6972 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6973 } 6974 6975 /* output arrays */ 6976 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6977 6978 /* get the point-to-point matrices; construct newPoints */ 6979 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6980 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6981 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6982 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6983 if (numFields) { 6984 for (p = 0, newP = 0; p < numPoints; p++) { 6985 PetscInt b = points[2*p]; 6986 PetscInt o = points[2*p+1]; 6987 PetscInt bDof = 0, bSecDof; 6988 6989 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6990 if (!bSecDof) { 6991 continue; 6992 } 6993 if (b >= aStart && b < aEnd) { 6994 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6995 } 6996 if (bDof) { 6997 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6998 6999 fStart[0] = 0; 7000 fEnd[0] = 0; 7001 for (f = 0; f < numFields; f++) { 7002 PetscInt fDof; 7003 7004 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7005 fStart[f+1] = fStart[f] + fDof; 7006 fEnd[f+1] = fStart[f+1]; 7007 } 7008 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7009 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7010 7011 fAnchorStart[0] = 0; 7012 fAnchorEnd[0] = 0; 7013 for (f = 0; f < numFields; f++) { 7014 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7015 7016 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7017 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7018 } 7019 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7020 for (q = 0; q < bDof; q++) { 7021 PetscInt a = anchors[bOff + q], aOff; 7022 7023 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7024 newPoints[2*(newP + q)] = a; 7025 newPoints[2*(newP + q) + 1] = 0; 7026 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7027 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7028 } 7029 newP += bDof; 7030 7031 if (outValues) { 7032 /* get the point-to-point submatrix */ 7033 for (f = 0; f < numFields; f++) { 7034 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7035 } 7036 } 7037 } 7038 else { 7039 newPoints[2 * newP] = b; 7040 newPoints[2 * newP + 1] = o; 7041 newP++; 7042 } 7043 } 7044 } else { 7045 for (p = 0; p < numPoints; p++) { 7046 PetscInt b = points[2*p]; 7047 PetscInt o = points[2*p+1]; 7048 PetscInt bDof = 0, bSecDof; 7049 7050 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7051 if (!bSecDof) { 7052 continue; 7053 } 7054 if (b >= aStart && b < aEnd) { 7055 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7056 } 7057 if (bDof) { 7058 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7059 7060 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7061 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7062 7063 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7064 for (q = 0; q < bDof; q++) { 7065 PetscInt a = anchors[bOff + q], aOff; 7066 7067 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7068 7069 newPoints[2*(newP + q)] = a; 7070 newPoints[2*(newP + q) + 1] = 0; 7071 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7072 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7073 } 7074 newP += bDof; 7075 7076 /* get the point-to-point submatrix */ 7077 if (outValues) { 7078 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7079 } 7080 } 7081 else { 7082 newPoints[2 * newP] = b; 7083 newPoints[2 * newP + 1] = o; 7084 newP++; 7085 } 7086 } 7087 } 7088 7089 if (outValues) { 7090 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7091 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7092 /* multiply constraints on the right */ 7093 if (numFields) { 7094 for (f = 0; f < numFields; f++) { 7095 PetscInt oldOff = offsets[f]; 7096 7097 for (p = 0; p < numPoints; p++) { 7098 PetscInt cStart = newPointOffsets[f][p]; 7099 PetscInt b = points[2 * p]; 7100 PetscInt c, r, k; 7101 PetscInt dof; 7102 7103 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7104 if (!dof) { 7105 continue; 7106 } 7107 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7108 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7109 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7110 7111 for (r = 0; r < numIndices; r++) { 7112 for (c = 0; c < nCols; c++) { 7113 for (k = 0; k < dof; k++) { 7114 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7115 } 7116 } 7117 } 7118 } 7119 else { 7120 /* copy this column as is */ 7121 for (r = 0; r < numIndices; r++) { 7122 for (c = 0; c < dof; c++) { 7123 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7124 } 7125 } 7126 } 7127 oldOff += dof; 7128 } 7129 } 7130 } 7131 else { 7132 PetscInt oldOff = 0; 7133 for (p = 0; p < numPoints; p++) { 7134 PetscInt cStart = newPointOffsets[0][p]; 7135 PetscInt b = points[2 * p]; 7136 PetscInt c, r, k; 7137 PetscInt dof; 7138 7139 PetscCall(PetscSectionGetDof(section,b,&dof)); 7140 if (!dof) { 7141 continue; 7142 } 7143 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7144 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7145 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7146 7147 for (r = 0; r < numIndices; r++) { 7148 for (c = 0; c < nCols; c++) { 7149 for (k = 0; k < dof; k++) { 7150 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7151 } 7152 } 7153 } 7154 } 7155 else { 7156 /* copy this column as is */ 7157 for (r = 0; r < numIndices; r++) { 7158 for (c = 0; c < dof; c++) { 7159 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7160 } 7161 } 7162 } 7163 oldOff += dof; 7164 } 7165 } 7166 7167 if (multiplyLeft) { 7168 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7169 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7170 /* multiply constraints transpose on the left */ 7171 if (numFields) { 7172 for (f = 0; f < numFields; f++) { 7173 PetscInt oldOff = offsets[f]; 7174 7175 for (p = 0; p < numPoints; p++) { 7176 PetscInt rStart = newPointOffsets[f][p]; 7177 PetscInt b = points[2 * p]; 7178 PetscInt c, r, k; 7179 PetscInt dof; 7180 7181 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7182 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7183 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7184 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7185 7186 for (r = 0; r < nRows; r++) { 7187 for (c = 0; c < newNumIndices; c++) { 7188 for (k = 0; k < dof; k++) { 7189 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7190 } 7191 } 7192 } 7193 } 7194 else { 7195 /* copy this row as is */ 7196 for (r = 0; r < dof; r++) { 7197 for (c = 0; c < newNumIndices; c++) { 7198 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7199 } 7200 } 7201 } 7202 oldOff += dof; 7203 } 7204 } 7205 } 7206 else { 7207 PetscInt oldOff = 0; 7208 7209 for (p = 0; p < numPoints; p++) { 7210 PetscInt rStart = newPointOffsets[0][p]; 7211 PetscInt b = points[2 * p]; 7212 PetscInt c, r, k; 7213 PetscInt dof; 7214 7215 PetscCall(PetscSectionGetDof(section,b,&dof)); 7216 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7217 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7218 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7219 7220 for (r = 0; r < nRows; r++) { 7221 for (c = 0; c < newNumIndices; c++) { 7222 for (k = 0; k < dof; k++) { 7223 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7224 } 7225 } 7226 } 7227 } 7228 else { 7229 /* copy this row as is */ 7230 for (r = 0; r < dof; r++) { 7231 for (c = 0; c < newNumIndices; c++) { 7232 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7233 } 7234 } 7235 } 7236 oldOff += dof; 7237 } 7238 } 7239 7240 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7241 } 7242 else { 7243 newValues = tmpValues; 7244 } 7245 } 7246 7247 /* clean up */ 7248 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7249 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7250 7251 if (numFields) { 7252 for (f = 0; f < numFields; f++) { 7253 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7254 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7255 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7256 } 7257 } 7258 else { 7259 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7260 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7261 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7262 } 7263 PetscCall(ISRestoreIndices(aIS,&anchors)); 7264 7265 /* output */ 7266 if (outPoints) { 7267 *outPoints = newPoints; 7268 } 7269 else { 7270 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7271 } 7272 if (outValues) { 7273 *outValues = newValues; 7274 } 7275 for (f = 0; f <= numFields; f++) { 7276 offsets[f] = newOffsets[f]; 7277 } 7278 PetscFunctionReturn(0); 7279 } 7280 7281 /*@C 7282 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7283 7284 Not collective 7285 7286 Input Parameters: 7287 + dm - The DM 7288 . section - The PetscSection describing the points (a local section) 7289 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7290 . point - The point defining the closure 7291 - useClPerm - Use the closure point permutation if available 7292 7293 Output Parameters: 7294 + numIndices - The number of dof indices in the closure of point with the input sections 7295 . indices - The dof indices 7296 . outOffsets - Array to write the field offsets into, or NULL 7297 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7298 7299 Notes: 7300 Must call DMPlexRestoreClosureIndices() to free allocated memory 7301 7302 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7303 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7304 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7305 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7306 indices (with the above semantics) are implied. 7307 7308 Level: advanced 7309 7310 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7311 @*/ 7312 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7313 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7314 { 7315 /* Closure ordering */ 7316 PetscSection clSection; 7317 IS clPoints; 7318 const PetscInt *clp; 7319 PetscInt *points; 7320 const PetscInt *clperm = NULL; 7321 /* Dof permutation and sign flips */ 7322 const PetscInt **perms[32] = {NULL}; 7323 const PetscScalar **flips[32] = {NULL}; 7324 PetscScalar *valCopy = NULL; 7325 /* Hanging node constraints */ 7326 PetscInt *pointsC = NULL; 7327 PetscScalar *valuesC = NULL; 7328 PetscInt NclC, NiC; 7329 7330 PetscInt *idx; 7331 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7332 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7333 7334 PetscFunctionBeginHot; 7335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7336 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7337 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7338 if (numIndices) PetscValidIntPointer(numIndices, 6); 7339 if (indices) PetscValidPointer(indices, 7); 7340 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7341 if (values) PetscValidPointer(values, 9); 7342 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7343 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7344 PetscCall(PetscArrayzero(offsets, 32)); 7345 /* 1) Get points in closure */ 7346 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7347 if (useClPerm) { 7348 PetscInt depth, clsize; 7349 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7350 for (clsize=0,p=0; p<Ncl; p++) { 7351 PetscInt dof; 7352 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7353 clsize += dof; 7354 } 7355 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7356 } 7357 /* 2) Get number of indices on these points and field offsets from section */ 7358 for (p = 0; p < Ncl*2; p += 2) { 7359 PetscInt dof, fdof; 7360 7361 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7362 for (f = 0; f < Nf; ++f) { 7363 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7364 offsets[f+1] += fdof; 7365 } 7366 Ni += dof; 7367 } 7368 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7369 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7370 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7371 for (f = 0; f < PetscMax(1, Nf); ++f) { 7372 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7373 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7374 /* may need to apply sign changes to the element matrix */ 7375 if (values && flips[f]) { 7376 PetscInt foffset = offsets[f]; 7377 7378 for (p = 0; p < Ncl; ++p) { 7379 PetscInt pnt = points[2*p], fdof; 7380 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7381 7382 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7383 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7384 if (flip) { 7385 PetscInt i, j, k; 7386 7387 if (!valCopy) { 7388 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7389 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7390 *values = valCopy; 7391 } 7392 for (i = 0; i < fdof; ++i) { 7393 PetscScalar fval = flip[i]; 7394 7395 for (k = 0; k < Ni; ++k) { 7396 valCopy[Ni * (foffset + i) + k] *= fval; 7397 valCopy[Ni * k + (foffset + i)] *= fval; 7398 } 7399 } 7400 } 7401 foffset += fdof; 7402 } 7403 } 7404 } 7405 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7406 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7407 if (NclC) { 7408 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7409 for (f = 0; f < PetscMax(1, Nf); ++f) { 7410 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7411 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7412 } 7413 for (f = 0; f < PetscMax(1, Nf); ++f) { 7414 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7415 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7416 } 7417 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7418 Ncl = NclC; 7419 Ni = NiC; 7420 points = pointsC; 7421 if (values) *values = valuesC; 7422 } 7423 /* 5) Calculate indices */ 7424 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7425 if (Nf) { 7426 PetscInt idxOff; 7427 PetscBool useFieldOffsets; 7428 7429 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7430 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7431 if (useFieldOffsets) { 7432 for (p = 0; p < Ncl; ++p) { 7433 const PetscInt pnt = points[p*2]; 7434 7435 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7436 } 7437 } else { 7438 for (p = 0; p < Ncl; ++p) { 7439 const PetscInt pnt = points[p*2]; 7440 7441 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7442 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7443 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7444 * global section. */ 7445 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7446 } 7447 } 7448 } else { 7449 PetscInt off = 0, idxOff; 7450 7451 for (p = 0; p < Ncl; ++p) { 7452 const PetscInt pnt = points[p*2]; 7453 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7454 7455 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7456 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7457 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7458 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7459 } 7460 } 7461 /* 6) Cleanup */ 7462 for (f = 0; f < PetscMax(1, Nf); ++f) { 7463 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7464 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7465 } 7466 if (NclC) { 7467 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7468 } else { 7469 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7470 } 7471 7472 if (numIndices) *numIndices = Ni; 7473 if (indices) *indices = idx; 7474 PetscFunctionReturn(0); 7475 } 7476 7477 /*@C 7478 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7479 7480 Not collective 7481 7482 Input Parameters: 7483 + dm - The DM 7484 . section - The PetscSection describing the points (a local section) 7485 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7486 . point - The point defining the closure 7487 - useClPerm - Use the closure point permutation if available 7488 7489 Output Parameters: 7490 + numIndices - The number of dof indices in the closure of point with the input sections 7491 . indices - The dof indices 7492 . outOffsets - Array to write the field offsets into, or NULL 7493 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7494 7495 Notes: 7496 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7497 7498 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7499 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7500 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7501 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7502 indices (with the above semantics) are implied. 7503 7504 Level: advanced 7505 7506 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7507 @*/ 7508 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7509 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7510 { 7511 PetscFunctionBegin; 7512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7513 PetscValidPointer(indices, 7); 7514 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7515 PetscFunctionReturn(0); 7516 } 7517 7518 /*@C 7519 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7520 7521 Not collective 7522 7523 Input Parameters: 7524 + dm - The DM 7525 . section - The section describing the layout in v, or NULL to use the default section 7526 . globalSection - The section describing the layout in v, or NULL to use the default global section 7527 . A - The matrix 7528 . point - The point in the DM 7529 . values - The array of values 7530 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7531 7532 Fortran Notes: 7533 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7534 7535 Level: intermediate 7536 7537 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7538 @*/ 7539 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7540 { 7541 DM_Plex *mesh = (DM_Plex*) dm->data; 7542 PetscInt *indices; 7543 PetscInt numIndices; 7544 const PetscScalar *valuesOrig = values; 7545 PetscErrorCode ierr; 7546 7547 PetscFunctionBegin; 7548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7549 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7550 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7551 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7552 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7553 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7554 7555 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7556 7557 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7558 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7559 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7560 if (ierr) { 7561 PetscMPIInt rank; 7562 7563 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7564 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7565 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7566 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7567 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7568 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7569 } 7570 if (mesh->printFEM > 1) { 7571 PetscInt i; 7572 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7573 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7574 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7575 } 7576 7577 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7578 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7579 PetscFunctionReturn(0); 7580 } 7581 7582 /*@C 7583 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7584 7585 Not collective 7586 7587 Input Parameters: 7588 + dmRow - The DM for the row fields 7589 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7590 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7591 . dmCol - The DM for the column fields 7592 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7593 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7594 . A - The matrix 7595 . point - The point in the DMs 7596 . values - The array of values 7597 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7598 7599 Level: intermediate 7600 7601 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7602 @*/ 7603 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7604 { 7605 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7606 PetscInt *indicesRow, *indicesCol; 7607 PetscInt numIndicesRow, numIndicesCol; 7608 const PetscScalar *valuesOrig = values; 7609 PetscErrorCode ierr; 7610 7611 PetscFunctionBegin; 7612 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7613 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7614 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7615 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7616 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7617 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7618 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7619 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7620 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7621 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7622 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7623 7624 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7625 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7626 7627 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7628 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7629 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7630 if (ierr) { 7631 PetscMPIInt rank; 7632 7633 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7634 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7635 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7636 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7637 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7638 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7639 } 7640 7641 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7642 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7643 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7644 PetscFunctionReturn(0); 7645 } 7646 7647 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7648 { 7649 DM_Plex *mesh = (DM_Plex*) dmf->data; 7650 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7651 PetscInt *cpoints = NULL; 7652 PetscInt *findices, *cindices; 7653 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7654 PetscInt foffsets[32], coffsets[32]; 7655 DMPolytopeType ct; 7656 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7657 PetscErrorCode ierr; 7658 7659 PetscFunctionBegin; 7660 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7661 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7662 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7663 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7664 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7665 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7666 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7667 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7668 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7669 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7670 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7671 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7672 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7673 PetscCall(PetscArrayzero(foffsets, 32)); 7674 PetscCall(PetscArrayzero(coffsets, 32)); 7675 /* Column indices */ 7676 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7677 maxFPoints = numCPoints; 7678 /* Compress out points not in the section */ 7679 /* TODO: Squeeze out points with 0 dof as well */ 7680 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7681 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7682 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7683 cpoints[q*2] = cpoints[p]; 7684 cpoints[q*2+1] = cpoints[p+1]; 7685 ++q; 7686 } 7687 } 7688 numCPoints = q; 7689 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7690 PetscInt fdof; 7691 7692 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7693 if (!dof) continue; 7694 for (f = 0; f < numFields; ++f) { 7695 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7696 coffsets[f+1] += fdof; 7697 } 7698 numCIndices += dof; 7699 } 7700 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7701 /* Row indices */ 7702 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7703 { 7704 DMPlexTransform tr; 7705 DMPolytopeType *rct; 7706 PetscInt *rsize, *rcone, *rornt, Nt; 7707 7708 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7709 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7710 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7711 numSubcells = rsize[Nt-1]; 7712 PetscCall(DMPlexTransformDestroy(&tr)); 7713 } 7714 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7715 for (r = 0, q = 0; r < numSubcells; ++r) { 7716 /* TODO Map from coarse to fine cells */ 7717 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7718 /* Compress out points not in the section */ 7719 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7720 for (p = 0; p < numFPoints*2; p += 2) { 7721 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7722 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7723 if (!dof) continue; 7724 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7725 if (s < q) continue; 7726 ftotpoints[q*2] = fpoints[p]; 7727 ftotpoints[q*2+1] = fpoints[p+1]; 7728 ++q; 7729 } 7730 } 7731 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7732 } 7733 numFPoints = q; 7734 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7735 PetscInt fdof; 7736 7737 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7738 if (!dof) continue; 7739 for (f = 0; f < numFields; ++f) { 7740 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7741 foffsets[f+1] += fdof; 7742 } 7743 numFIndices += dof; 7744 } 7745 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7746 7747 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7748 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7749 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7750 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7751 if (numFields) { 7752 const PetscInt **permsF[32] = {NULL}; 7753 const PetscInt **permsC[32] = {NULL}; 7754 7755 for (f = 0; f < numFields; f++) { 7756 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7757 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7758 } 7759 for (p = 0; p < numFPoints; p++) { 7760 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7761 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7762 } 7763 for (p = 0; p < numCPoints; p++) { 7764 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7765 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7766 } 7767 for (f = 0; f < numFields; f++) { 7768 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7769 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7770 } 7771 } else { 7772 const PetscInt **permsF = NULL; 7773 const PetscInt **permsC = NULL; 7774 7775 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7776 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7777 for (p = 0, off = 0; p < numFPoints; p++) { 7778 const PetscInt *perm = permsF ? permsF[p] : NULL; 7779 7780 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7781 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7782 } 7783 for (p = 0, off = 0; p < numCPoints; p++) { 7784 const PetscInt *perm = permsC ? permsC[p] : NULL; 7785 7786 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7787 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7788 } 7789 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7790 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7791 } 7792 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7793 /* TODO: flips */ 7794 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7795 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7796 if (ierr) { 7797 PetscMPIInt rank; 7798 7799 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7800 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7801 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7802 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7803 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7804 } 7805 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7806 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7807 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7808 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7809 PetscFunctionReturn(0); 7810 } 7811 7812 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7813 { 7814 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7815 PetscInt *cpoints = NULL; 7816 PetscInt foffsets[32], coffsets[32]; 7817 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7818 DMPolytopeType ct; 7819 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7820 7821 PetscFunctionBegin; 7822 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7823 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7824 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7825 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7826 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7827 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7828 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7829 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7830 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7831 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7832 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7833 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7834 PetscCall(PetscArrayzero(foffsets, 32)); 7835 PetscCall(PetscArrayzero(coffsets, 32)); 7836 /* Column indices */ 7837 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7838 maxFPoints = numCPoints; 7839 /* Compress out points not in the section */ 7840 /* TODO: Squeeze out points with 0 dof as well */ 7841 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7842 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7843 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7844 cpoints[q*2] = cpoints[p]; 7845 cpoints[q*2+1] = cpoints[p+1]; 7846 ++q; 7847 } 7848 } 7849 numCPoints = q; 7850 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7851 PetscInt fdof; 7852 7853 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7854 if (!dof) continue; 7855 for (f = 0; f < numFields; ++f) { 7856 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7857 coffsets[f+1] += fdof; 7858 } 7859 numCIndices += dof; 7860 } 7861 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7862 /* Row indices */ 7863 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7864 { 7865 DMPlexTransform tr; 7866 DMPolytopeType *rct; 7867 PetscInt *rsize, *rcone, *rornt, Nt; 7868 7869 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7870 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7871 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7872 numSubcells = rsize[Nt-1]; 7873 PetscCall(DMPlexTransformDestroy(&tr)); 7874 } 7875 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7876 for (r = 0, q = 0; r < numSubcells; ++r) { 7877 /* TODO Map from coarse to fine cells */ 7878 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7879 /* Compress out points not in the section */ 7880 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7881 for (p = 0; p < numFPoints*2; p += 2) { 7882 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7883 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7884 if (!dof) continue; 7885 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7886 if (s < q) continue; 7887 ftotpoints[q*2] = fpoints[p]; 7888 ftotpoints[q*2+1] = fpoints[p+1]; 7889 ++q; 7890 } 7891 } 7892 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7893 } 7894 numFPoints = q; 7895 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7896 PetscInt fdof; 7897 7898 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7899 if (!dof) continue; 7900 for (f = 0; f < numFields; ++f) { 7901 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7902 foffsets[f+1] += fdof; 7903 } 7904 numFIndices += dof; 7905 } 7906 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7907 7908 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7909 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7910 if (numFields) { 7911 const PetscInt **permsF[32] = {NULL}; 7912 const PetscInt **permsC[32] = {NULL}; 7913 7914 for (f = 0; f < numFields; f++) { 7915 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7916 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7917 } 7918 for (p = 0; p < numFPoints; p++) { 7919 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7920 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7921 } 7922 for (p = 0; p < numCPoints; p++) { 7923 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7924 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7925 } 7926 for (f = 0; f < numFields; f++) { 7927 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7928 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7929 } 7930 } else { 7931 const PetscInt **permsF = NULL; 7932 const PetscInt **permsC = NULL; 7933 7934 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7935 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7936 for (p = 0, off = 0; p < numFPoints; p++) { 7937 const PetscInt *perm = permsF ? permsF[p] : NULL; 7938 7939 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7940 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7941 } 7942 for (p = 0, off = 0; p < numCPoints; p++) { 7943 const PetscInt *perm = permsC ? permsC[p] : NULL; 7944 7945 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7946 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7947 } 7948 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7949 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7950 } 7951 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7952 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7953 PetscFunctionReturn(0); 7954 } 7955 7956 /*@C 7957 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7958 7959 Input Parameter: 7960 . dm - The DMPlex object 7961 7962 Output Parameter: 7963 . cellHeight - The height of a cell 7964 7965 Level: developer 7966 7967 .seealso `DMPlexSetVTKCellHeight()` 7968 @*/ 7969 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7970 { 7971 DM_Plex *mesh = (DM_Plex*) dm->data; 7972 7973 PetscFunctionBegin; 7974 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7975 PetscValidIntPointer(cellHeight, 2); 7976 *cellHeight = mesh->vtkCellHeight; 7977 PetscFunctionReturn(0); 7978 } 7979 7980 /*@C 7981 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7982 7983 Input Parameters: 7984 + dm - The DMPlex object 7985 - cellHeight - The height of a cell 7986 7987 Level: developer 7988 7989 .seealso `DMPlexGetVTKCellHeight()` 7990 @*/ 7991 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7992 { 7993 DM_Plex *mesh = (DM_Plex*) dm->data; 7994 7995 PetscFunctionBegin; 7996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7997 mesh->vtkCellHeight = cellHeight; 7998 PetscFunctionReturn(0); 7999 } 8000 8001 /*@ 8002 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8003 8004 Input Parameter: 8005 . dm - The DMPlex object 8006 8007 Output Parameters: 8008 + gcStart - The first ghost cell, or NULL 8009 - gcEnd - The upper bound on ghost cells, or NULL 8010 8011 Level: advanced 8012 8013 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8014 @*/ 8015 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8016 { 8017 DMLabel ctLabel; 8018 8019 PetscFunctionBegin; 8020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8021 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8022 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8023 PetscFunctionReturn(0); 8024 } 8025 8026 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8027 { 8028 PetscSection section, globalSection; 8029 PetscInt *numbers, p; 8030 8031 PetscFunctionBegin; 8032 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8033 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8034 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8035 for (p = pStart; p < pEnd; ++p) { 8036 PetscCall(PetscSectionSetDof(section, p, 1)); 8037 } 8038 PetscCall(PetscSectionSetUp(section)); 8039 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8040 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8041 for (p = pStart; p < pEnd; ++p) { 8042 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8043 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8044 else numbers[p-pStart] += shift; 8045 } 8046 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8047 if (globalSize) { 8048 PetscLayout layout; 8049 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8050 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8051 PetscCall(PetscLayoutDestroy(&layout)); 8052 } 8053 PetscCall(PetscSectionDestroy(§ion)); 8054 PetscCall(PetscSectionDestroy(&globalSection)); 8055 PetscFunctionReturn(0); 8056 } 8057 8058 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8059 { 8060 PetscInt cellHeight, cStart, cEnd; 8061 8062 PetscFunctionBegin; 8063 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8064 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8065 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8066 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8067 PetscFunctionReturn(0); 8068 } 8069 8070 /*@ 8071 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8072 8073 Input Parameter: 8074 . dm - The DMPlex object 8075 8076 Output Parameter: 8077 . globalCellNumbers - Global cell numbers for all cells on this process 8078 8079 Level: developer 8080 8081 .seealso `DMPlexGetVertexNumbering()` 8082 @*/ 8083 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8084 { 8085 DM_Plex *mesh = (DM_Plex*) dm->data; 8086 8087 PetscFunctionBegin; 8088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8089 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8090 *globalCellNumbers = mesh->globalCellNumbers; 8091 PetscFunctionReturn(0); 8092 } 8093 8094 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8095 { 8096 PetscInt vStart, vEnd; 8097 8098 PetscFunctionBegin; 8099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8100 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8101 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8102 PetscFunctionReturn(0); 8103 } 8104 8105 /*@ 8106 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8107 8108 Input Parameter: 8109 . dm - The DMPlex object 8110 8111 Output Parameter: 8112 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8113 8114 Level: developer 8115 8116 .seealso `DMPlexGetCellNumbering()` 8117 @*/ 8118 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8119 { 8120 DM_Plex *mesh = (DM_Plex*) dm->data; 8121 8122 PetscFunctionBegin; 8123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8124 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8125 *globalVertexNumbers = mesh->globalVertexNumbers; 8126 PetscFunctionReturn(0); 8127 } 8128 8129 /*@ 8130 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8131 8132 Input Parameter: 8133 . dm - The DMPlex object 8134 8135 Output Parameter: 8136 . globalPointNumbers - Global numbers for all points on this process 8137 8138 Level: developer 8139 8140 .seealso `DMPlexGetCellNumbering()` 8141 @*/ 8142 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8143 { 8144 IS nums[4]; 8145 PetscInt depths[4], gdepths[4], starts[4]; 8146 PetscInt depth, d, shift = 0; 8147 8148 PetscFunctionBegin; 8149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8150 PetscCall(DMPlexGetDepth(dm, &depth)); 8151 /* For unstratified meshes use dim instead of depth */ 8152 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8153 for (d = 0; d <= depth; ++d) { 8154 PetscInt end; 8155 8156 depths[d] = depth-d; 8157 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8158 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8159 } 8160 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8161 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8162 for (d = 0; d <= depth; ++d) { 8163 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]); 8164 } 8165 for (d = 0; d <= depth; ++d) { 8166 PetscInt pStart, pEnd, gsize; 8167 8168 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8169 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8170 shift += gsize; 8171 } 8172 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8173 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8174 PetscFunctionReturn(0); 8175 } 8176 8177 /*@ 8178 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8179 8180 Input Parameter: 8181 . dm - The DMPlex object 8182 8183 Output Parameter: 8184 . ranks - The rank field 8185 8186 Options Database Keys: 8187 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8188 8189 Level: intermediate 8190 8191 .seealso: `DMView()` 8192 @*/ 8193 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8194 { 8195 DM rdm; 8196 PetscFE fe; 8197 PetscScalar *r; 8198 PetscMPIInt rank; 8199 DMPolytopeType ct; 8200 PetscInt dim, cStart, cEnd, c; 8201 PetscBool simplex; 8202 8203 PetscFunctionBeginUser; 8204 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8205 PetscValidPointer(ranks, 2); 8206 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8207 PetscCall(DMClone(dm, &rdm)); 8208 PetscCall(DMGetDimension(rdm, &dim)); 8209 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8210 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8211 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8212 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8213 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8214 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8215 PetscCall(PetscFEDestroy(&fe)); 8216 PetscCall(DMCreateDS(rdm)); 8217 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8218 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8219 PetscCall(VecGetArray(*ranks, &r)); 8220 for (c = cStart; c < cEnd; ++c) { 8221 PetscScalar *lr; 8222 8223 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8224 if (lr) *lr = rank; 8225 } 8226 PetscCall(VecRestoreArray(*ranks, &r)); 8227 PetscCall(DMDestroy(&rdm)); 8228 PetscFunctionReturn(0); 8229 } 8230 8231 /*@ 8232 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8233 8234 Input Parameters: 8235 + dm - The DMPlex 8236 - label - The DMLabel 8237 8238 Output Parameter: 8239 . val - The label value field 8240 8241 Options Database Keys: 8242 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8243 8244 Level: intermediate 8245 8246 .seealso: `DMView()` 8247 @*/ 8248 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8249 { 8250 DM rdm; 8251 PetscFE fe; 8252 PetscScalar *v; 8253 PetscInt dim, cStart, cEnd, c; 8254 8255 PetscFunctionBeginUser; 8256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8257 PetscValidPointer(label, 2); 8258 PetscValidPointer(val, 3); 8259 PetscCall(DMClone(dm, &rdm)); 8260 PetscCall(DMGetDimension(rdm, &dim)); 8261 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8262 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8263 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8264 PetscCall(PetscFEDestroy(&fe)); 8265 PetscCall(DMCreateDS(rdm)); 8266 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8267 PetscCall(DMCreateGlobalVector(rdm, val)); 8268 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8269 PetscCall(VecGetArray(*val, &v)); 8270 for (c = cStart; c < cEnd; ++c) { 8271 PetscScalar *lv; 8272 PetscInt cval; 8273 8274 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8275 PetscCall(DMLabelGetValue(label, c, &cval)); 8276 *lv = cval; 8277 } 8278 PetscCall(VecRestoreArray(*val, &v)); 8279 PetscCall(DMDestroy(&rdm)); 8280 PetscFunctionReturn(0); 8281 } 8282 8283 /*@ 8284 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8285 8286 Input Parameter: 8287 . dm - The DMPlex object 8288 8289 Notes: 8290 This is a useful diagnostic when creating meshes programmatically. 8291 8292 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8293 8294 Level: developer 8295 8296 .seealso: `DMCreate()`, `DMSetFromOptions()` 8297 @*/ 8298 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8299 { 8300 PetscSection coneSection, supportSection; 8301 const PetscInt *cone, *support; 8302 PetscInt coneSize, c, supportSize, s; 8303 PetscInt pStart, pEnd, p, pp, csize, ssize; 8304 PetscBool storagecheck = PETSC_TRUE; 8305 8306 PetscFunctionBegin; 8307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8308 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8309 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8310 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8311 /* Check that point p is found in the support of its cone points, and vice versa */ 8312 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8313 for (p = pStart; p < pEnd; ++p) { 8314 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8315 PetscCall(DMPlexGetCone(dm, p, &cone)); 8316 for (c = 0; c < coneSize; ++c) { 8317 PetscBool dup = PETSC_FALSE; 8318 PetscInt d; 8319 for (d = c-1; d >= 0; --d) { 8320 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8321 } 8322 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8323 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8324 for (s = 0; s < supportSize; ++s) { 8325 if (support[s] == p) break; 8326 } 8327 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8329 for (s = 0; s < coneSize; ++s) { 8330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8331 } 8332 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8334 for (s = 0; s < supportSize; ++s) { 8335 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8336 } 8337 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8338 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]); 8339 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8340 } 8341 } 8342 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8343 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8344 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8345 PetscCall(DMPlexGetSupport(dm, p, &support)); 8346 for (s = 0; s < supportSize; ++s) { 8347 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8348 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8349 for (c = 0; c < coneSize; ++c) { 8350 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8351 if (cone[c] != pp) { c = 0; break; } 8352 if (cone[c] == p) break; 8353 } 8354 if (c >= coneSize) { 8355 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8356 for (c = 0; c < supportSize; ++c) { 8357 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8358 } 8359 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8360 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8361 for (c = 0; c < coneSize; ++c) { 8362 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8363 } 8364 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8365 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8366 } 8367 } 8368 } 8369 if (storagecheck) { 8370 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8371 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8372 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8373 } 8374 PetscFunctionReturn(0); 8375 } 8376 8377 /* 8378 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. 8379 */ 8380 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8381 { 8382 DMPolytopeType cct; 8383 PetscInt ptpoints[4]; 8384 const PetscInt *cone, *ccone, *ptcone; 8385 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8386 8387 PetscFunctionBegin; 8388 *unsplit = 0; 8389 switch (ct) { 8390 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8391 ptpoints[npt++] = c; 8392 break; 8393 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8394 PetscCall(DMPlexGetCone(dm, c, &cone)); 8395 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8396 for (cp = 0; cp < coneSize; ++cp) { 8397 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8398 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8399 } 8400 break; 8401 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8402 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8403 PetscCall(DMPlexGetCone(dm, c, &cone)); 8404 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8405 for (cp = 0; cp < coneSize; ++cp) { 8406 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8407 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8408 for (ccp = 0; ccp < cconeSize; ++ccp) { 8409 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8410 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8411 PetscInt p; 8412 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8413 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8414 } 8415 } 8416 } 8417 break; 8418 default: break; 8419 } 8420 for (pt = 0; pt < npt; ++pt) { 8421 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8422 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8423 } 8424 PetscFunctionReturn(0); 8425 } 8426 8427 /*@ 8428 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8429 8430 Input Parameters: 8431 + dm - The DMPlex object 8432 - cellHeight - Normally 0 8433 8434 Notes: 8435 This is a useful diagnostic when creating meshes programmatically. 8436 Currently applicable only to homogeneous simplex or tensor meshes. 8437 8438 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8439 8440 Level: developer 8441 8442 .seealso: `DMCreate()`, `DMSetFromOptions()` 8443 @*/ 8444 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8445 { 8446 DMPlexInterpolatedFlag interp; 8447 DMPolytopeType ct; 8448 PetscInt vStart, vEnd, cStart, cEnd, c; 8449 8450 PetscFunctionBegin; 8451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8452 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8453 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8454 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8455 for (c = cStart; c < cEnd; ++c) { 8456 PetscInt *closure = NULL; 8457 PetscInt coneSize, closureSize, cl, Nv = 0; 8458 8459 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8460 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8461 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8462 if (interp == DMPLEX_INTERPOLATED_FULL) { 8463 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8464 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)); 8465 } 8466 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8467 for (cl = 0; cl < closureSize*2; cl += 2) { 8468 const PetscInt p = closure[cl]; 8469 if ((p >= vStart) && (p < vEnd)) ++Nv; 8470 } 8471 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8472 /* Special Case: Tensor faces with identified vertices */ 8473 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8474 PetscInt unsplit; 8475 8476 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8477 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8478 } 8479 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)); 8480 } 8481 PetscFunctionReturn(0); 8482 } 8483 8484 /*@ 8485 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8486 8487 Collective 8488 8489 Input Parameters: 8490 + dm - The DMPlex object 8491 - cellHeight - Normally 0 8492 8493 Notes: 8494 This is a useful diagnostic when creating meshes programmatically. 8495 This routine is only relevant for meshes that are fully interpolated across all ranks. 8496 It will error out if a partially interpolated mesh is given on some rank. 8497 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8498 8499 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8500 8501 Level: developer 8502 8503 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8504 @*/ 8505 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8506 { 8507 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8508 DMPlexInterpolatedFlag interpEnum; 8509 8510 PetscFunctionBegin; 8511 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8512 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8513 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8514 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8515 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8516 PetscFunctionReturn(0); 8517 } 8518 8519 PetscCall(DMGetDimension(dm, &dim)); 8520 PetscCall(DMPlexGetDepth(dm, &depth)); 8521 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8522 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8523 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8524 for (c = cStart; c < cEnd; ++c) { 8525 const PetscInt *cone, *ornt, *faceSizes, *faces; 8526 const DMPolytopeType *faceTypes; 8527 DMPolytopeType ct; 8528 PetscInt numFaces, coneSize, f; 8529 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8530 8531 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8532 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8533 if (unsplit) continue; 8534 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8535 PetscCall(DMPlexGetCone(dm, c, &cone)); 8536 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8537 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8538 for (cl = 0; cl < closureSize*2; cl += 2) { 8539 const PetscInt p = closure[cl]; 8540 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8541 } 8542 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8543 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); 8544 for (f = 0; f < numFaces; ++f) { 8545 DMPolytopeType fct; 8546 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8547 8548 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8549 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8550 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8551 const PetscInt p = fclosure[cl]; 8552 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8553 } 8554 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]); 8555 for (v = 0; v < fnumCorners; ++v) { 8556 if (fclosure[v] != faces[fOff+v]) { 8557 PetscInt v1; 8558 8559 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8560 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8561 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8562 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8563 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8564 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]); 8565 } 8566 } 8567 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8568 fOff += faceSizes[f]; 8569 } 8570 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8571 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8572 } 8573 } 8574 PetscFunctionReturn(0); 8575 } 8576 8577 /*@ 8578 DMPlexCheckGeometry - Check the geometry of mesh cells 8579 8580 Input Parameter: 8581 . dm - The DMPlex object 8582 8583 Notes: 8584 This is a useful diagnostic when creating meshes programmatically. 8585 8586 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8587 8588 Level: developer 8589 8590 .seealso: `DMCreate()`, `DMSetFromOptions()` 8591 @*/ 8592 PetscErrorCode DMPlexCheckGeometry(DM dm) 8593 { 8594 Vec coordinates; 8595 PetscReal detJ, J[9], refVol = 1.0; 8596 PetscReal vol; 8597 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8598 8599 PetscFunctionBegin; 8600 PetscCall(DMGetDimension(dm, &dim)); 8601 PetscCall(DMGetCoordinateDim(dm, &dE)); 8602 if (dim != dE) PetscFunctionReturn(0); 8603 PetscCall(DMPlexGetDepth(dm, &depth)); 8604 for (d = 0; d < dim; ++d) refVol *= 2.0; 8605 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8606 /* Make sure local coordinates are created, because that step is collective */ 8607 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8608 for (c = cStart; c < cEnd; ++c) { 8609 DMPolytopeType ct; 8610 PetscInt unsplit; 8611 PetscBool ignoreZeroVol = PETSC_FALSE; 8612 8613 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8614 switch (ct) { 8615 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8616 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8617 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8618 ignoreZeroVol = PETSC_TRUE; break; 8619 default: break; 8620 } 8621 switch (ct) { 8622 case DM_POLYTOPE_TRI_PRISM: 8623 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8624 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8625 case DM_POLYTOPE_PYRAMID: 8626 continue; 8627 default: break; 8628 } 8629 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8630 if (unsplit) continue; 8631 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8632 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); 8633 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8634 /* This should work with periodicity since DG coordinates should be used */ 8635 if (depth > 1) { 8636 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8637 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); 8638 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8639 } 8640 } 8641 PetscFunctionReturn(0); 8642 } 8643 8644 /*@ 8645 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8646 8647 Collective 8648 8649 Input Parameters: 8650 + dm - The DMPlex object 8651 - pointSF - The Point SF, or NULL for Point SF attached to DM 8652 8653 Notes: 8654 This is mainly intended for debugging/testing purposes. 8655 8656 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8657 8658 Level: developer 8659 8660 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8661 @*/ 8662 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8663 { 8664 PetscInt l, nleaves, nroots, overlap; 8665 const PetscInt *locals; 8666 const PetscSFNode *remotes; 8667 PetscBool distributed; 8668 MPI_Comm comm; 8669 PetscMPIInt rank; 8670 8671 PetscFunctionBegin; 8672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8673 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8674 else pointSF = dm->sf; 8675 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8676 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8677 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8678 { 8679 PetscMPIInt mpiFlag; 8680 8681 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8682 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8683 } 8684 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8685 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8686 if (!distributed) { 8687 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); 8688 PetscFunctionReturn(0); 8689 } 8690 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); 8691 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8692 8693 /* Check SF graph is compatible with DMPlex chart */ 8694 { 8695 PetscInt pStart, pEnd, maxLeaf; 8696 8697 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8698 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8699 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8700 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8701 } 8702 8703 /* Check Point SF has no local points referenced */ 8704 for (l = 0; l < nleaves; l++) { 8705 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); 8706 } 8707 8708 /* Check there are no cells in interface */ 8709 if (!overlap) { 8710 PetscInt cellHeight, cStart, cEnd; 8711 8712 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8713 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8714 for (l = 0; l < nleaves; ++l) { 8715 const PetscInt point = locals ? locals[l] : l; 8716 8717 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8718 } 8719 } 8720 8721 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8722 { 8723 const PetscInt *rootdegree; 8724 8725 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8726 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8727 for (l = 0; l < nleaves; ++l) { 8728 const PetscInt point = locals ? locals[l] : l; 8729 const PetscInt *cone; 8730 PetscInt coneSize, c, idx; 8731 8732 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8733 PetscCall(DMPlexGetCone(dm, point, &cone)); 8734 for (c = 0; c < coneSize; ++c) { 8735 if (!rootdegree[cone[c]]) { 8736 if (locals) { 8737 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8738 } else { 8739 idx = (cone[c] < nleaves) ? cone[c] : -1; 8740 } 8741 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8742 } 8743 } 8744 } 8745 } 8746 PetscFunctionReturn(0); 8747 } 8748 8749 /*@ 8750 DMPlexCheck - Perform various checks of Plex sanity 8751 8752 Input Parameter: 8753 . dm - The DMPlex object 8754 8755 Notes: 8756 This is a useful diagnostic when creating meshes programmatically. 8757 8758 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8759 8760 Currently does not include DMPlexCheckCellShape(). 8761 8762 Level: developer 8763 8764 .seealso: DMCreate(), DMSetFromOptions() 8765 @*/ 8766 PetscErrorCode DMPlexCheck(DM dm) 8767 { 8768 PetscInt cellHeight; 8769 8770 PetscFunctionBegin; 8771 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8772 PetscCall(DMPlexCheckSymmetry(dm)); 8773 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8774 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8775 PetscCall(DMPlexCheckGeometry(dm)); 8776 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8777 PetscCall(DMPlexCheckInterfaceCones(dm)); 8778 PetscFunctionReturn(0); 8779 } 8780 8781 typedef struct cell_stats 8782 { 8783 PetscReal min, max, sum, squaresum; 8784 PetscInt count; 8785 } cell_stats_t; 8786 8787 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8788 { 8789 PetscInt i, N = *len; 8790 8791 for (i = 0; i < N; i++) { 8792 cell_stats_t *A = (cell_stats_t *) a; 8793 cell_stats_t *B = (cell_stats_t *) b; 8794 8795 B->min = PetscMin(A->min,B->min); 8796 B->max = PetscMax(A->max,B->max); 8797 B->sum += A->sum; 8798 B->squaresum += A->squaresum; 8799 B->count += A->count; 8800 } 8801 } 8802 8803 /*@ 8804 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8805 8806 Collective on dm 8807 8808 Input Parameters: 8809 + dm - The DMPlex object 8810 . output - If true, statistics will be displayed on stdout 8811 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8812 8813 Notes: 8814 This is mainly intended for debugging/testing purposes. 8815 8816 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8817 8818 Level: developer 8819 8820 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8821 @*/ 8822 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8823 { 8824 DM dmCoarse; 8825 cell_stats_t stats, globalStats; 8826 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8827 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8828 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8829 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8830 PetscMPIInt rank,size; 8831 8832 PetscFunctionBegin; 8833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8834 stats.min = PETSC_MAX_REAL; 8835 stats.max = PETSC_MIN_REAL; 8836 stats.sum = stats.squaresum = 0.; 8837 stats.count = 0; 8838 8839 PetscCallMPI(MPI_Comm_size(comm, &size)); 8840 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8841 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8842 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8843 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8844 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8845 for (c = cStart; c < cEnd; c++) { 8846 PetscInt i; 8847 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8848 8849 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8850 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8851 for (i = 0; i < PetscSqr(cdim); ++i) { 8852 frobJ += J[i] * J[i]; 8853 frobInvJ += invJ[i] * invJ[i]; 8854 } 8855 cond2 = frobJ * frobInvJ; 8856 cond = PetscSqrtReal(cond2); 8857 8858 stats.min = PetscMin(stats.min,cond); 8859 stats.max = PetscMax(stats.max,cond); 8860 stats.sum += cond; 8861 stats.squaresum += cond2; 8862 stats.count++; 8863 if (output && cond > limit) { 8864 PetscSection coordSection; 8865 Vec coordsLocal; 8866 PetscScalar *coords = NULL; 8867 PetscInt Nv, d, clSize, cl, *closure = NULL; 8868 8869 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8870 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8871 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8872 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8873 for (i = 0; i < Nv/cdim; ++i) { 8874 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8875 for (d = 0; d < cdim; ++d) { 8876 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8877 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8878 } 8879 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8880 } 8881 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8882 for (cl = 0; cl < clSize*2; cl += 2) { 8883 const PetscInt edge = closure[cl]; 8884 8885 if ((edge >= eStart) && (edge < eEnd)) { 8886 PetscReal len; 8887 8888 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8889 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8890 } 8891 } 8892 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8893 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8894 } 8895 } 8896 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8897 8898 if (size > 1) { 8899 PetscMPIInt blockLengths[2] = {4,1}; 8900 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8901 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8902 MPI_Op statReduce; 8903 8904 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8905 PetscCallMPI(MPI_Type_commit(&statType)); 8906 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8907 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8908 PetscCallMPI(MPI_Op_free(&statReduce)); 8909 PetscCallMPI(MPI_Type_free(&statType)); 8910 } else { 8911 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8912 } 8913 if (rank == 0) { 8914 count = globalStats.count; 8915 min = globalStats.min; 8916 max = globalStats.max; 8917 mean = globalStats.sum / globalStats.count; 8918 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8919 } 8920 8921 if (output) { 8922 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)); 8923 } 8924 PetscCall(PetscFree2(J,invJ)); 8925 8926 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8927 if (dmCoarse) { 8928 PetscBool isplex; 8929 8930 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8931 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8932 } 8933 PetscFunctionReturn(0); 8934 } 8935 8936 /*@ 8937 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8938 orthogonal quality below given tolerance. 8939 8940 Collective on dm 8941 8942 Input Parameters: 8943 + dm - The DMPlex object 8944 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8945 - atol - [0, 1] Absolute tolerance for tagging cells. 8946 8947 Output Parameters: 8948 + OrthQual - Vec containing orthogonal quality per cell 8949 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8950 8951 Options Database Keys: 8952 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8953 supported. 8954 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8955 8956 Notes: 8957 Orthogonal quality is given by the following formula: 8958 8959 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8960 8961 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 8962 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8963 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8964 calculating the cosine of the angle between these vectors. 8965 8966 Orthogonal quality ranges from 1 (best) to 0 (worst). 8967 8968 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8969 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8970 8971 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8972 8973 Level: intermediate 8974 8975 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8976 @*/ 8977 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8978 { 8979 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8980 PetscInt *idx; 8981 PetscScalar *oqVals; 8982 const PetscScalar *cellGeomArr, *faceGeomArr; 8983 PetscReal *ci, *fi, *Ai; 8984 MPI_Comm comm; 8985 Vec cellgeom, facegeom; 8986 DM dmFace, dmCell; 8987 IS glob; 8988 ISLocalToGlobalMapping ltog; 8989 PetscViewer vwr; 8990 8991 PetscFunctionBegin; 8992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8993 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8994 PetscValidPointer(OrthQual, 4); 8995 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8996 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8997 PetscCall(DMGetDimension(dm, &nc)); 8998 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8999 { 9000 DMPlexInterpolatedFlag interpFlag; 9001 9002 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9003 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9004 PetscMPIInt rank; 9005 9006 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9007 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9008 } 9009 } 9010 if (OrthQualLabel) { 9011 PetscValidPointer(OrthQualLabel, 5); 9012 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9013 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9014 } else {*OrthQualLabel = NULL;} 9015 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9016 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9017 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9018 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9019 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9020 PetscCall(VecCreate(comm, OrthQual)); 9021 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9022 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9023 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9024 PetscCall(VecSetUp(*OrthQual)); 9025 PetscCall(ISDestroy(&glob)); 9026 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9027 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9028 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9029 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9030 PetscCall(VecGetDM(cellgeom, &dmCell)); 9031 PetscCall(VecGetDM(facegeom, &dmFace)); 9032 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9033 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9034 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9035 PetscInt cellarr[2], *adj = NULL; 9036 PetscScalar *cArr, *fArr; 9037 PetscReal minvalc = 1.0, minvalf = 1.0; 9038 PetscFVCellGeom *cg; 9039 9040 idx[cellIter] = cell-cStart; 9041 cellarr[0] = cell; 9042 /* Make indexing into cellGeom easier */ 9043 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9044 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9045 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9046 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9047 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9048 PetscInt i; 9049 const PetscInt neigh = adj[cellneigh]; 9050 PetscReal normci = 0, normfi = 0, normai = 0; 9051 PetscFVCellGeom *cgneigh; 9052 PetscFVFaceGeom *fg; 9053 9054 /* Don't count ourselves in the neighbor list */ 9055 if (neigh == cell) continue; 9056 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9057 cellarr[1] = neigh; 9058 { 9059 PetscInt numcovpts; 9060 const PetscInt *covpts; 9061 9062 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9063 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9064 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9065 } 9066 9067 /* Compute c_i, f_i and their norms */ 9068 for (i = 0; i < nc; i++) { 9069 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9070 fi[i] = fg->centroid[i] - cg->centroid[i]; 9071 Ai[i] = fg->normal[i]; 9072 normci += PetscPowReal(ci[i], 2); 9073 normfi += PetscPowReal(fi[i], 2); 9074 normai += PetscPowReal(Ai[i], 2); 9075 } 9076 normci = PetscSqrtReal(normci); 9077 normfi = PetscSqrtReal(normfi); 9078 normai = PetscSqrtReal(normai); 9079 9080 /* Normalize and compute for each face-cell-normal pair */ 9081 for (i = 0; i < nc; i++) { 9082 ci[i] = ci[i]/normci; 9083 fi[i] = fi[i]/normfi; 9084 Ai[i] = Ai[i]/normai; 9085 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9086 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9087 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9088 } 9089 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9090 minvalc = PetscRealPart(cArr[cellneighiter]); 9091 } 9092 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9093 minvalf = PetscRealPart(fArr[cellneighiter]); 9094 } 9095 } 9096 PetscCall(PetscFree(adj)); 9097 PetscCall(PetscFree2(cArr, fArr)); 9098 /* Defer to cell if they're equal */ 9099 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9100 if (OrthQualLabel) { 9101 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9102 } 9103 } 9104 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9105 PetscCall(VecAssemblyBegin(*OrthQual)); 9106 PetscCall(VecAssemblyEnd(*OrthQual)); 9107 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9108 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9109 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9110 if (OrthQualLabel) { 9111 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9112 } 9113 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9114 PetscCall(PetscViewerDestroy(&vwr)); 9115 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9116 PetscFunctionReturn(0); 9117 } 9118 9119 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9120 * interpolator construction */ 9121 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9122 { 9123 PetscSection section, newSection, gsection; 9124 PetscSF sf; 9125 PetscBool hasConstraints, ghasConstraints; 9126 9127 PetscFunctionBegin; 9128 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9129 PetscValidPointer(odm,2); 9130 PetscCall(DMGetLocalSection(dm, §ion)); 9131 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9132 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9133 if (!ghasConstraints) { 9134 PetscCall(PetscObjectReference((PetscObject)dm)); 9135 *odm = dm; 9136 PetscFunctionReturn(0); 9137 } 9138 PetscCall(DMClone(dm, odm)); 9139 PetscCall(DMCopyFields(dm, *odm)); 9140 PetscCall(DMGetLocalSection(*odm, &newSection)); 9141 PetscCall(DMGetPointSF(*odm, &sf)); 9142 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9143 PetscCall(DMSetGlobalSection(*odm, gsection)); 9144 PetscCall(PetscSectionDestroy(&gsection)); 9145 PetscFunctionReturn(0); 9146 } 9147 9148 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9149 { 9150 DM dmco, dmfo; 9151 Mat interpo; 9152 Vec rscale; 9153 Vec cglobalo, clocal; 9154 Vec fglobal, fglobalo, flocal; 9155 PetscBool regular; 9156 9157 PetscFunctionBegin; 9158 PetscCall(DMGetFullDM(dmc, &dmco)); 9159 PetscCall(DMGetFullDM(dmf, &dmfo)); 9160 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9161 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9162 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9163 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9164 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9165 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9166 PetscCall(VecSet(cglobalo, 0.)); 9167 PetscCall(VecSet(clocal, 0.)); 9168 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9169 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9170 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9171 PetscCall(VecSet(fglobal, 0.)); 9172 PetscCall(VecSet(fglobalo, 0.)); 9173 PetscCall(VecSet(flocal, 0.)); 9174 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9175 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9176 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9177 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9178 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9179 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9180 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9181 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9182 *shift = fglobal; 9183 PetscCall(VecDestroy(&flocal)); 9184 PetscCall(VecDestroy(&fglobalo)); 9185 PetscCall(VecDestroy(&clocal)); 9186 PetscCall(VecDestroy(&cglobalo)); 9187 PetscCall(VecDestroy(&rscale)); 9188 PetscCall(MatDestroy(&interpo)); 9189 PetscCall(DMDestroy(&dmfo)); 9190 PetscCall(DMDestroy(&dmco)); 9191 PetscFunctionReturn(0); 9192 } 9193 9194 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9195 { 9196 PetscObject shifto; 9197 Vec shift; 9198 9199 PetscFunctionBegin; 9200 if (!interp) { 9201 Vec rscale; 9202 9203 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9204 PetscCall(VecDestroy(&rscale)); 9205 } else { 9206 PetscCall(PetscObjectReference((PetscObject)interp)); 9207 } 9208 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9209 if (!shifto) { 9210 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9211 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9212 shifto = (PetscObject) shift; 9213 PetscCall(VecDestroy(&shift)); 9214 } 9215 shift = (Vec) shifto; 9216 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9217 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9218 PetscCall(MatDestroy(&interp)); 9219 PetscFunctionReturn(0); 9220 } 9221 9222 /* Pointwise interpolation 9223 Just code FEM for now 9224 u^f = I u^c 9225 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9226 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9227 I_{ij} = psi^f_i phi^c_j 9228 */ 9229 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9230 { 9231 PetscSection gsc, gsf; 9232 PetscInt m, n; 9233 void *ctx; 9234 DM cdm; 9235 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9236 9237 PetscFunctionBegin; 9238 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9239 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9240 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9241 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9242 9243 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9244 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9245 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9246 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9247 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9248 9249 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9250 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9251 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9252 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9253 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9254 if (scaling) { 9255 /* Use naive scaling */ 9256 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9257 } 9258 PetscFunctionReturn(0); 9259 } 9260 9261 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9262 { 9263 VecScatter ctx; 9264 9265 PetscFunctionBegin; 9266 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9267 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9268 PetscCall(VecScatterDestroy(&ctx)); 9269 PetscFunctionReturn(0); 9270 } 9271 9272 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9273 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9274 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9275 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9276 { 9277 const PetscInt Nc = uOff[1] - uOff[0]; 9278 PetscInt c; 9279 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9280 } 9281 9282 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9283 { 9284 DM dmc; 9285 PetscDS ds; 9286 Vec ones, locmass; 9287 IS cellIS; 9288 PetscFormKey key; 9289 PetscInt depth; 9290 9291 PetscFunctionBegin; 9292 PetscCall(DMClone(dm, &dmc)); 9293 PetscCall(DMCopyDisc(dm, dmc)); 9294 PetscCall(DMGetDS(dmc, &ds)); 9295 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9296 PetscCall(DMCreateGlobalVector(dmc, mass)); 9297 PetscCall(DMGetLocalVector(dmc, &ones)); 9298 PetscCall(DMGetLocalVector(dmc, &locmass)); 9299 PetscCall(DMPlexGetDepth(dmc, &depth)); 9300 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9301 PetscCall(VecSet(locmass, 0.0)); 9302 PetscCall(VecSet(ones, 1.0)); 9303 key.label = NULL; 9304 key.value = 0; 9305 key.field = 0; 9306 key.part = 0; 9307 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9308 PetscCall(ISDestroy(&cellIS)); 9309 PetscCall(VecSet(*mass, 0.0)); 9310 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9311 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9312 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9313 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9314 PetscCall(DMDestroy(&dmc)); 9315 PetscFunctionReturn(0); 9316 } 9317 9318 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9319 { 9320 PetscSection gsc, gsf; 9321 PetscInt m, n; 9322 void *ctx; 9323 DM cdm; 9324 PetscBool regular; 9325 9326 PetscFunctionBegin; 9327 if (dmFine == dmCoarse) { 9328 DM dmc; 9329 PetscDS ds; 9330 PetscWeakForm wf; 9331 Vec u; 9332 IS cellIS; 9333 PetscFormKey key; 9334 PetscInt depth; 9335 9336 PetscCall(DMClone(dmFine, &dmc)); 9337 PetscCall(DMCopyDisc(dmFine, dmc)); 9338 PetscCall(DMGetDS(dmc, &ds)); 9339 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9340 PetscCall(PetscWeakFormClear(wf)); 9341 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9342 PetscCall(DMCreateMatrix(dmc, mass)); 9343 PetscCall(DMGetGlobalVector(dmc, &u)); 9344 PetscCall(DMPlexGetDepth(dmc, &depth)); 9345 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9346 PetscCall(MatZeroEntries(*mass)); 9347 key.label = NULL; 9348 key.value = 0; 9349 key.field = 0; 9350 key.part = 0; 9351 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9352 PetscCall(ISDestroy(&cellIS)); 9353 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9354 PetscCall(DMDestroy(&dmc)); 9355 } else { 9356 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9357 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9358 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9359 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9360 9361 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9362 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9363 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9364 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9365 9366 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9367 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9368 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9369 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9370 } 9371 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9372 PetscFunctionReturn(0); 9373 } 9374 9375 /*@ 9376 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9377 9378 Input Parameter: 9379 . dm - The DMPlex object 9380 9381 Output Parameter: 9382 . regular - The flag 9383 9384 Level: intermediate 9385 9386 .seealso: `DMPlexSetRegularRefinement()` 9387 @*/ 9388 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9389 { 9390 PetscFunctionBegin; 9391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9392 PetscValidBoolPointer(regular, 2); 9393 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9394 PetscFunctionReturn(0); 9395 } 9396 9397 /*@ 9398 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9399 9400 Input Parameters: 9401 + dm - The DMPlex object 9402 - regular - The flag 9403 9404 Level: intermediate 9405 9406 .seealso: `DMPlexGetRegularRefinement()` 9407 @*/ 9408 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9409 { 9410 PetscFunctionBegin; 9411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9412 ((DM_Plex *) dm->data)->regularRefinement = regular; 9413 PetscFunctionReturn(0); 9414 } 9415 9416 /* anchors */ 9417 /*@ 9418 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9419 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9420 9421 not collective 9422 9423 Input Parameter: 9424 . dm - The DMPlex object 9425 9426 Output Parameters: 9427 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9428 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9429 9430 Level: intermediate 9431 9432 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9433 @*/ 9434 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9435 { 9436 DM_Plex *plex = (DM_Plex *)dm->data; 9437 9438 PetscFunctionBegin; 9439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9440 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9441 if (anchorSection) *anchorSection = plex->anchorSection; 9442 if (anchorIS) *anchorIS = plex->anchorIS; 9443 PetscFunctionReturn(0); 9444 } 9445 9446 /*@ 9447 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9448 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9449 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9450 9451 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9452 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9453 9454 collective on dm 9455 9456 Input Parameters: 9457 + dm - The DMPlex object 9458 . 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). 9459 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9460 9461 The reference counts of anchorSection and anchorIS are incremented. 9462 9463 Level: intermediate 9464 9465 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9466 @*/ 9467 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9468 { 9469 DM_Plex *plex = (DM_Plex *)dm->data; 9470 PetscMPIInt result; 9471 9472 PetscFunctionBegin; 9473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9474 if (anchorSection) { 9475 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9476 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9477 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9478 } 9479 if (anchorIS) { 9480 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9481 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9482 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9483 } 9484 9485 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9486 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9487 plex->anchorSection = anchorSection; 9488 9489 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9490 PetscCall(ISDestroy(&plex->anchorIS)); 9491 plex->anchorIS = anchorIS; 9492 9493 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9494 PetscInt size, a, pStart, pEnd; 9495 const PetscInt *anchors; 9496 9497 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9498 PetscCall(ISGetLocalSize(anchorIS,&size)); 9499 PetscCall(ISGetIndices(anchorIS,&anchors)); 9500 for (a = 0; a < size; a++) { 9501 PetscInt p; 9502 9503 p = anchors[a]; 9504 if (p >= pStart && p < pEnd) { 9505 PetscInt dof; 9506 9507 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9508 if (dof) { 9509 9510 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9511 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9512 } 9513 } 9514 } 9515 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9516 } 9517 /* reset the generic constraints */ 9518 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9519 PetscFunctionReturn(0); 9520 } 9521 9522 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9523 { 9524 PetscSection anchorSection; 9525 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9526 9527 PetscFunctionBegin; 9528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9529 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9530 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9531 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9532 if (numFields) { 9533 PetscInt f; 9534 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9535 9536 for (f = 0; f < numFields; f++) { 9537 PetscInt numComp; 9538 9539 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9540 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9541 } 9542 } 9543 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9544 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9545 pStart = PetscMax(pStart,sStart); 9546 pEnd = PetscMin(pEnd,sEnd); 9547 pEnd = PetscMax(pStart,pEnd); 9548 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9549 for (p = pStart; p < pEnd; p++) { 9550 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9551 if (dof) { 9552 PetscCall(PetscSectionGetDof(section,p,&dof)); 9553 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9554 for (f = 0; f < numFields; f++) { 9555 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9556 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9557 } 9558 } 9559 } 9560 PetscCall(PetscSectionSetUp(*cSec)); 9561 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9562 PetscFunctionReturn(0); 9563 } 9564 9565 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9566 { 9567 PetscSection aSec; 9568 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9569 const PetscInt *anchors; 9570 PetscInt numFields, f; 9571 IS aIS; 9572 MatType mtype; 9573 PetscBool iscuda,iskokkos; 9574 9575 PetscFunctionBegin; 9576 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9577 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9578 PetscCall(PetscSectionGetStorageSize(section, &n)); 9579 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9580 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9581 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9582 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9583 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9584 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9585 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9586 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9587 else mtype = MATSEQAIJ; 9588 PetscCall(MatSetType(*cMat,mtype)); 9589 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9590 PetscCall(ISGetIndices(aIS,&anchors)); 9591 /* cSec will be a subset of aSec and section */ 9592 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9593 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9594 PetscCall(PetscMalloc1(m+1,&i)); 9595 i[0] = 0; 9596 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9597 for (p = pStart; p < pEnd; p++) { 9598 PetscInt rDof, rOff, r; 9599 9600 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9601 if (!rDof) continue; 9602 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9603 if (numFields) { 9604 for (f = 0; f < numFields; f++) { 9605 annz = 0; 9606 for (r = 0; r < rDof; r++) { 9607 a = anchors[rOff + r]; 9608 if (a < sStart || a >= sEnd) continue; 9609 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9610 annz += aDof; 9611 } 9612 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9613 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9614 for (q = 0; q < dof; q++) { 9615 i[off + q + 1] = i[off + q] + annz; 9616 } 9617 } 9618 } else { 9619 annz = 0; 9620 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9621 for (q = 0; q < dof; q++) { 9622 a = anchors[rOff + q]; 9623 if (a < sStart || a >= sEnd) continue; 9624 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9625 annz += aDof; 9626 } 9627 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9628 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9629 for (q = 0; q < dof; q++) { 9630 i[off + q + 1] = i[off + q] + annz; 9631 } 9632 } 9633 } 9634 nnz = i[m]; 9635 PetscCall(PetscMalloc1(nnz,&j)); 9636 offset = 0; 9637 for (p = pStart; p < pEnd; p++) { 9638 if (numFields) { 9639 for (f = 0; f < numFields; f++) { 9640 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9641 for (q = 0; q < dof; q++) { 9642 PetscInt rDof, rOff, r; 9643 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9644 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9645 for (r = 0; r < rDof; r++) { 9646 PetscInt s; 9647 9648 a = anchors[rOff + r]; 9649 if (a < sStart || a >= sEnd) continue; 9650 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9651 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9652 for (s = 0; s < aDof; s++) { 9653 j[offset++] = aOff + s; 9654 } 9655 } 9656 } 9657 } 9658 } else { 9659 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9660 for (q = 0; q < dof; q++) { 9661 PetscInt rDof, rOff, r; 9662 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9663 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9664 for (r = 0; r < rDof; r++) { 9665 PetscInt s; 9666 9667 a = anchors[rOff + r]; 9668 if (a < sStart || a >= sEnd) continue; 9669 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9670 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9671 for (s = 0; s < aDof; s++) { 9672 j[offset++] = aOff + s; 9673 } 9674 } 9675 } 9676 } 9677 } 9678 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9679 PetscCall(PetscFree(i)); 9680 PetscCall(PetscFree(j)); 9681 PetscCall(ISRestoreIndices(aIS,&anchors)); 9682 PetscFunctionReturn(0); 9683 } 9684 9685 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9686 { 9687 DM_Plex *plex = (DM_Plex *)dm->data; 9688 PetscSection anchorSection, section, cSec; 9689 Mat cMat; 9690 9691 PetscFunctionBegin; 9692 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9693 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9694 if (anchorSection) { 9695 PetscInt Nf; 9696 9697 PetscCall(DMGetLocalSection(dm,§ion)); 9698 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9699 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9700 PetscCall(DMGetNumFields(dm,&Nf)); 9701 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9702 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9703 PetscCall(PetscSectionDestroy(&cSec)); 9704 PetscCall(MatDestroy(&cMat)); 9705 } 9706 PetscFunctionReturn(0); 9707 } 9708 9709 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9710 { 9711 IS subis; 9712 PetscSection section, subsection; 9713 9714 PetscFunctionBegin; 9715 PetscCall(DMGetLocalSection(dm, §ion)); 9716 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9717 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9718 /* Create subdomain */ 9719 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9720 /* Create submodel */ 9721 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9722 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9723 PetscCall(DMSetLocalSection(*subdm, subsection)); 9724 PetscCall(PetscSectionDestroy(&subsection)); 9725 PetscCall(DMCopyDisc(dm, *subdm)); 9726 /* Create map from submodel to global model */ 9727 if (is) { 9728 PetscSection sectionGlobal, subsectionGlobal; 9729 IS spIS; 9730 const PetscInt *spmap; 9731 PetscInt *subIndices; 9732 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9733 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9734 9735 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9736 PetscCall(ISGetIndices(spIS, &spmap)); 9737 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9738 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9739 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9740 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9741 for (p = pStart; p < pEnd; ++p) { 9742 PetscInt gdof, pSubSize = 0; 9743 9744 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9745 if (gdof > 0) { 9746 for (f = 0; f < Nf; ++f) { 9747 PetscInt fdof, fcdof; 9748 9749 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9750 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9751 pSubSize += fdof-fcdof; 9752 } 9753 subSize += pSubSize; 9754 if (pSubSize) { 9755 if (bs < 0) { 9756 bs = pSubSize; 9757 } else if (bs != pSubSize) { 9758 /* Layout does not admit a pointwise block size */ 9759 bs = 1; 9760 } 9761 } 9762 } 9763 } 9764 /* Must have same blocksize on all procs (some might have no points) */ 9765 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9766 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9767 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9768 else {bs = bsMinMax[0];} 9769 PetscCall(PetscMalloc1(subSize, &subIndices)); 9770 for (p = pStart; p < pEnd; ++p) { 9771 PetscInt gdof, goff; 9772 9773 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9774 if (gdof > 0) { 9775 const PetscInt point = spmap[p]; 9776 9777 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9778 for (f = 0; f < Nf; ++f) { 9779 PetscInt fdof, fcdof, fc, f2, poff = 0; 9780 9781 /* Can get rid of this loop by storing field information in the global section */ 9782 for (f2 = 0; f2 < f; ++f2) { 9783 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9784 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9785 poff += fdof-fcdof; 9786 } 9787 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9788 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9789 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9790 subIndices[subOff] = goff+poff+fc; 9791 } 9792 } 9793 } 9794 } 9795 PetscCall(ISRestoreIndices(spIS, &spmap)); 9796 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9797 if (bs > 1) { 9798 /* We need to check that the block size does not come from non-contiguous fields */ 9799 PetscInt i, j, set = 1; 9800 for (i = 0; i < subSize; i += bs) { 9801 for (j = 0; j < bs; ++j) { 9802 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9803 } 9804 } 9805 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9806 } 9807 /* Attach nullspace */ 9808 for (f = 0; f < Nf; ++f) { 9809 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9810 if ((*subdm)->nullspaceConstructors[f]) break; 9811 } 9812 if (f < Nf) { 9813 MatNullSpace nullSpace; 9814 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9815 9816 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9817 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9818 } 9819 } 9820 PetscFunctionReturn(0); 9821 } 9822 9823 /*@ 9824 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9825 9826 Input Parameter: 9827 - dm - The DM 9828 9829 Level: developer 9830 9831 Options Database Keys: 9832 . -dm_plex_monitor_throughput - Activate the monitor 9833 9834 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9835 @*/ 9836 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9837 { 9838 #if defined(PETSC_USE_LOG) 9839 PetscStageLog stageLog; 9840 PetscLogEvent event; 9841 PetscLogStage stage; 9842 PetscEventPerfInfo eventInfo; 9843 PetscReal cellRate, flopRate; 9844 PetscInt cStart, cEnd, Nf, N; 9845 const char *name; 9846 #endif 9847 9848 PetscFunctionBegin; 9849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9850 #if defined(PETSC_USE_LOG) 9851 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9852 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9853 PetscCall(DMGetNumFields(dm, &Nf)); 9854 PetscCall(PetscLogGetStageLog(&stageLog)); 9855 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9856 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9857 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9858 N = (cEnd - cStart)*Nf*eventInfo.count; 9859 flopRate = eventInfo.flops/eventInfo.time; 9860 cellRate = N/eventInfo.time; 9861 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))); 9862 #else 9863 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9864 #endif 9865 PetscFunctionReturn(0); 9866 } 9867