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