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 { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 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 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 929 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 930 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 931 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 932 if (!useLabels) numLabels = 0; 933 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 934 if (!useColors) { 935 numColors = 3; 936 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 937 } 938 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 939 if (!useColors) { 940 numLColors = 4; 941 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 942 } 943 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 944 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 945 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 946 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 994 } 995 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 996 } 997 if (drawHasse) { 998 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 999 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1001 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1003 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1012 } 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1014 1015 /* Plot vertices */ 1016 PetscCall(VecGetArray(coordinates, &coords)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 for (v = vStart; v < vEnd; ++v) { 1019 PetscInt off, dof, d; 1020 PetscBool isLabeled = PETSC_FALSE; 1021 1022 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1023 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1025 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1026 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1027 for (d = 0; d < dof; ++d) { 1028 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1029 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1030 } 1031 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1032 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1033 for (d = 0; d < dof; ++d) { 1034 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1036 } 1037 if (drawHasse) color = colors[0%numColors]; 1038 else color = colors[rank%numColors]; 1039 for (l = 0; l < numLabels; ++l) { 1040 PetscInt val; 1041 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1042 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1043 } 1044 if (drawNumbers[0]) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1046 } else if (drawColors[0]) { 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1048 } else { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1050 } 1051 } 1052 PetscCall(VecRestoreArray(coordinates, &coords)); 1053 PetscCall(PetscViewerFlush(viewer)); 1054 /* Plot edges */ 1055 if (plotEdges) { 1056 PetscCall(VecGetArray(coordinates, &coords)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1058 for (e = eStart; e < eEnd; ++e) { 1059 const PetscInt *cone; 1060 PetscInt coneSize, offA, offB, dof, d; 1061 1062 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1063 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1064 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1065 PetscCall(DMPlexGetCone(dm, e, &cone)); 1066 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1067 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1068 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1070 for (d = 0; d < dof; ++d) { 1071 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1072 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1073 } 1074 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1075 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1076 for (d = 0; d < dof; ++d) { 1077 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1079 } 1080 if (drawHasse) color = colors[1%numColors]; 1081 else color = colors[rank%numColors]; 1082 for (l = 0; l < numLabels; ++l) { 1083 PetscInt val; 1084 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1085 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1086 } 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1088 } 1089 PetscCall(VecRestoreArray(coordinates, &coords)); 1090 PetscCall(PetscViewerFlush(viewer)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1092 } 1093 /* Plot cells */ 1094 if (dim == 3 || !drawNumbers[1]) { 1095 for (e = eStart; e < eEnd; ++e) { 1096 const PetscInt *cone; 1097 1098 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1099 color = colors[rank%numColors]; 1100 for (l = 0; l < numLabels; ++l) { 1101 PetscInt val; 1102 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1103 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1104 } 1105 PetscCall(DMPlexGetCone(dm, e, &cone)); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1107 } 1108 } else { 1109 DMPolytopeType ct; 1110 1111 /* Drawing a 2D polygon */ 1112 for (c = cStart; c < cEnd; ++c) { 1113 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1115 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1116 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1117 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, e; 1120 1121 PetscCall(DMPlexGetCone(dm, c, &cone)); 1122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1123 for (e = 0; e < coneSize; ++e) { 1124 const PetscInt *econe; 1125 1126 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1127 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)); 1128 } 1129 } else { 1130 PetscInt *closure = NULL; 1131 PetscInt closureSize, Nv = 0, v; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize*2; p += 2) { 1135 const PetscInt point = closure[p]; 1136 1137 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1138 } 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1140 for (v = 0; v <= Nv; ++v) { 1141 const PetscInt vertex = closure[v%Nv]; 1142 1143 if (v > 0) { 1144 if (plotEdges) { 1145 const PetscInt *edge; 1146 PetscInt endpoints[2], ne; 1147 1148 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1149 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1150 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1152 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1153 } else { 1154 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1155 } 1156 } 1157 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1158 } 1159 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 PetscCall(VecGetArray(coordinates, &coords)); 1165 for (c = cStart; c < cEnd; ++c) { 1166 double ccoords[3] = {0.0, 0.0, 0.0}; 1167 PetscBool isLabeled = PETSC_FALSE; 1168 PetscInt *closure = NULL; 1169 PetscInt closureSize, dof, d, n = 0; 1170 1171 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1172 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1174 for (p = 0; p < closureSize*2; p += 2) { 1175 const PetscInt point = closure[p]; 1176 PetscInt off; 1177 1178 if ((point < vStart) || (point >= vEnd)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1181 for (d = 0; d < dof; ++d) { 1182 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1183 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1184 } 1185 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1186 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1187 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1188 ++n; 1189 } 1190 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1191 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1195 } 1196 if (drawHasse) color = colors[depth%numColors]; 1197 else color = colors[rank%numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1201 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1202 } 1203 if (drawNumbers[dim]) { 1204 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1205 } else if (drawColors[dim]) { 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1207 } else { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1209 } 1210 } 1211 PetscCall(VecRestoreArray(coordinates, &coords)); 1212 if (drawHasse) { 1213 color = colors[depth%numColors]; 1214 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1215 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1216 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1217 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1219 1220 color = colors[1%numColors]; 1221 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1226 1227 color = colors[0%numColors]; 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1233 1234 for (p = pStart; p < pEnd; ++p) { 1235 const PetscInt *cone; 1236 PetscInt coneSize, cp; 1237 1238 PetscCall(DMPlexGetCone(dm, p, &cone)); 1239 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1240 for (cp = 0; cp < coneSize; ++cp) { 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1242 } 1243 } 1244 } 1245 PetscCall(PetscViewerFlush(viewer)); 1246 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1249 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1250 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1251 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1252 PetscCall(PetscFree3(names, colors, lcolors)); 1253 PetscCall(PetscBTDestroy(&wp)); 1254 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1255 Vec cown,acown; 1256 VecScatter sct; 1257 ISLocalToGlobalMapping g2l; 1258 IS gid,acis; 1259 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1260 MPI_Group ggroup,ngroup; 1261 PetscScalar *array,nid; 1262 const PetscInt *idxs; 1263 PetscInt *idxs2,*start,*adjacency,*work; 1264 PetscInt64 lm[3],gm[3]; 1265 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1266 PetscMPIInt d1,d2,rank; 1267 1268 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1269 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1270 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1271 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1272 #endif 1273 if (ncomm != MPI_COMM_NULL) { 1274 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1275 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1276 d1 = 0; 1277 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1278 nid = d2; 1279 PetscCallMPI(MPI_Group_free(&ggroup)); 1280 PetscCallMPI(MPI_Group_free(&ngroup)); 1281 PetscCallMPI(MPI_Comm_free(&ncomm)); 1282 } else nid = 0.0; 1283 1284 /* Get connectivity */ 1285 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1286 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1287 1288 /* filter overlapped local cells */ 1289 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1290 PetscCall(ISGetIndices(gid,&idxs)); 1291 PetscCall(ISGetLocalSize(gid,&cum)); 1292 PetscCall(PetscMalloc1(cum,&idxs2)); 1293 for (c = cStart, cum = 0; c < cEnd; c++) { 1294 if (idxs[c-cStart] < 0) continue; 1295 idxs2[cum++] = idxs[c-cStart]; 1296 } 1297 PetscCall(ISRestoreIndices(gid,&idxs)); 1298 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1299 PetscCall(ISDestroy(&gid)); 1300 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1301 1302 /* support for node-aware cell locality */ 1303 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1304 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1305 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1306 PetscCall(VecGetArray(cown,&array)); 1307 for (c = 0; c < numVertices; c++) array[c] = nid; 1308 PetscCall(VecRestoreArray(cown,&array)); 1309 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1310 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1311 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1312 PetscCall(ISDestroy(&acis)); 1313 PetscCall(VecScatterDestroy(&sct)); 1314 PetscCall(VecDestroy(&cown)); 1315 1316 /* compute edgeCut */ 1317 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1318 PetscCall(PetscMalloc1(cum,&work)); 1319 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1320 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1321 PetscCall(ISDestroy(&gid)); 1322 PetscCall(VecGetArray(acown,&array)); 1323 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1324 PetscInt totl; 1325 1326 totl = start[c+1]-start[c]; 1327 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1328 for (i = 0; i < totl; i++) { 1329 if (work[i] < 0) { 1330 ect += 1; 1331 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1332 } 1333 } 1334 } 1335 PetscCall(PetscFree(work)); 1336 PetscCall(VecRestoreArray(acown,&array)); 1337 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1338 lm[1] = -numVertices; 1339 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1340 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1341 lm[0] = ect; /* edgeCut */ 1342 lm[1] = ectn; /* node-aware edgeCut */ 1343 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1344 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1345 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1346 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1347 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1348 #else 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1350 #endif 1351 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1352 PetscCall(PetscFree(start)); 1353 PetscCall(PetscFree(adjacency)); 1354 PetscCall(VecDestroy(&acown)); 1355 } else { 1356 const char *name; 1357 PetscInt *sizes, *hybsizes, *ghostsizes; 1358 PetscInt locDepth, depth, cellHeight, dim, d; 1359 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1360 PetscInt numLabels, l, maxSize = 17; 1361 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1362 MPI_Comm comm; 1363 PetscMPIInt size, rank; 1364 1365 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1366 PetscCallMPI(MPI_Comm_size(comm, &size)); 1367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1368 PetscCall(DMGetDimension(dm, &dim)); 1369 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1370 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1371 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1372 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1373 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1374 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1375 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1376 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1377 gcNum = gcEnd - gcStart; 1378 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1379 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1380 for (d = 0; d <= depth; d++) { 1381 PetscInt Nc[2] = {0, 0}, ict; 1382 1383 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1384 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1385 ict = ct0; 1386 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1387 ct0 = (DMPolytopeType) ict; 1388 for (p = pStart; p < pEnd; ++p) { 1389 DMPolytopeType ct; 1390 1391 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1392 if (ct == ct0) ++Nc[0]; 1393 else ++Nc[1]; 1394 } 1395 if (size < maxSize) { 1396 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1397 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1398 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1400 for (p = 0; p < size; ++p) { 1401 if (rank == 0) { 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1403 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1404 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1405 } 1406 } 1407 } else { 1408 PetscInt locMinMax[2]; 1409 1410 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1411 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1412 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1413 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1414 if (d == depth) { 1415 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1416 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1417 } 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1420 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1421 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1422 } 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1424 } 1425 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1426 { 1427 const PetscReal *maxCell; 1428 const PetscReal *L; 1429 const DMBoundaryType *bd; 1430 PetscBool per, localized; 1431 1432 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1433 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1434 if (per) { 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1436 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1437 for (d = 0; d < dim; ++d) { 1438 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1439 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1440 } 1441 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1442 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1443 } 1444 } 1445 PetscCall(DMGetNumLabels(dm, &numLabels)); 1446 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1447 for (l = 0; l < numLabels; ++l) { 1448 DMLabel label; 1449 const char *name; 1450 IS valueIS; 1451 const PetscInt *values; 1452 PetscInt numValues, v; 1453 1454 PetscCall(DMGetLabelName(dm, l, &name)); 1455 PetscCall(DMGetLabel(dm, name, &label)); 1456 PetscCall(DMLabelGetNumValues(label, &numValues)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1459 PetscCall(ISGetIndices(valueIS, &values)); 1460 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1461 for (v = 0; v < numValues; ++v) { 1462 PetscInt size; 1463 1464 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1465 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1467 } 1468 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1469 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1470 PetscCall(ISRestoreIndices(valueIS, &values)); 1471 PetscCall(ISDestroy(&valueIS)); 1472 } 1473 { 1474 char **labelNames; 1475 PetscInt Nl = numLabels; 1476 PetscBool flg; 1477 1478 PetscCall(PetscMalloc1(Nl, &labelNames)); 1479 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1480 for (l = 0; l < Nl; ++l) { 1481 DMLabel label; 1482 1483 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1484 if (flg) { 1485 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1486 PetscCall(DMLabelView(label, viewer)); 1487 } 1488 PetscCall(PetscFree(labelNames[l])); 1489 } 1490 PetscCall(PetscFree(labelNames)); 1491 } 1492 /* If no fields are specified, people do not want to see adjacency */ 1493 if (dm->Nf) { 1494 PetscInt f; 1495 1496 for (f = 0; f < dm->Nf; ++f) { 1497 const char *name; 1498 1499 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1500 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1501 PetscCall(PetscViewerASCIIPushTab(viewer)); 1502 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1503 if (dm->fields[f].adjacency[0]) { 1504 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1505 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1506 } else { 1507 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1508 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1509 } 1510 PetscCall(PetscViewerASCIIPopTab(viewer)); 1511 } 1512 } 1513 PetscCall(DMGetCoarseDM(dm, &cdm)); 1514 if (cdm) { 1515 PetscCall(PetscViewerASCIIPushTab(viewer)); 1516 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1517 PetscCall(PetscViewerASCIIPopTab(viewer)); 1518 } 1519 } 1520 PetscFunctionReturn(0); 1521 } 1522 1523 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1524 { 1525 DMPolytopeType ct; 1526 PetscMPIInt rank; 1527 PetscInt cdim; 1528 1529 PetscFunctionBegin; 1530 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1531 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1532 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1533 switch (ct) { 1534 case DM_POLYTOPE_SEGMENT: 1535 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1536 switch (cdim) { 1537 case 1: 1538 { 1539 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1540 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1541 1542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1543 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1544 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1545 } 1546 break; 1547 case 2: 1548 { 1549 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1550 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1551 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1554 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)); 1555 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)); 1556 } 1557 break; 1558 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1559 } 1560 break; 1561 case DM_POLYTOPE_TRIANGLE: 1562 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1563 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1564 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1565 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1569 break; 1570 case DM_POLYTOPE_QUADRILATERAL: 1571 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1572 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1573 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1583 break; 1584 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1585 } 1586 PetscFunctionReturn(0); 1587 } 1588 1589 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1590 { 1591 DMPolytopeType ct; 1592 PetscReal centroid[2] = {0., 0.}; 1593 PetscMPIInt rank; 1594 PetscInt fillColor, v, e, d; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1600 switch (ct) { 1601 case DM_POLYTOPE_TRIANGLE: 1602 { 1603 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1604 1605 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1606 for (e = 0; e < 3; ++e) { 1607 refCoords[0] = refVertices[e*2+0]; 1608 refCoords[1] = refVertices[e*2+1]; 1609 for (d = 1; d <= edgeDiv; ++d) { 1610 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1611 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1612 } 1613 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1614 for (d = 0; d < edgeDiv; ++d) { 1615 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)); 1616 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1617 } 1618 } 1619 } 1620 break; 1621 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1622 } 1623 PetscFunctionReturn(0); 1624 } 1625 1626 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1627 { 1628 PetscDraw draw; 1629 DM cdm; 1630 PetscSection coordSection; 1631 Vec coordinates; 1632 const PetscScalar *coords; 1633 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1634 PetscReal *refCoords, *edgeCoords; 1635 PetscBool isnull, drawAffine = PETSC_TRUE; 1636 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1637 1638 PetscFunctionBegin; 1639 PetscCall(DMGetCoordinateDim(dm, &dim)); 1640 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1641 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1642 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1643 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1644 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1645 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1646 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1647 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1648 1649 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1650 PetscCall(PetscDrawIsNull(draw, &isnull)); 1651 if (isnull) PetscFunctionReturn(0); 1652 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1653 1654 PetscCall(VecGetLocalSize(coordinates, &N)); 1655 PetscCall(VecGetArrayRead(coordinates, &coords)); 1656 for (c = 0; c < N; c += dim) { 1657 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1658 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1659 } 1660 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1661 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1662 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1663 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1664 PetscCall(PetscDrawClear(draw)); 1665 1666 for (c = cStart; c < cEnd; ++c) { 1667 PetscScalar *coords = NULL; 1668 PetscInt numCoords; 1669 1670 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1671 if (drawAffine) { 1672 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1673 } else { 1674 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1675 } 1676 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1677 } 1678 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1679 PetscCall(PetscDrawFlush(draw)); 1680 PetscCall(PetscDrawPause(draw)); 1681 PetscCall(PetscDrawSave(draw)); 1682 PetscFunctionReturn(0); 1683 } 1684 1685 #if defined(PETSC_HAVE_EXODUSII) 1686 #include <exodusII.h> 1687 #include <petscviewerexodusii.h> 1688 #endif 1689 1690 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1691 { 1692 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1693 char name[PETSC_MAX_PATH_LEN]; 1694 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1697 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1698 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1699 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1704 if (iascii) { 1705 PetscViewerFormat format; 1706 PetscCall(PetscViewerGetFormat(viewer, &format)); 1707 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1708 PetscCall(DMPlexView_GLVis(dm, viewer)); 1709 } else { 1710 PetscCall(DMPlexView_Ascii(dm, viewer)); 1711 } 1712 } else if (ishdf5) { 1713 #if defined(PETSC_HAVE_HDF5) 1714 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1715 #else 1716 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1717 #endif 1718 } else if (isvtk) { 1719 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1720 } else if (isdraw) { 1721 PetscCall(DMPlexView_Draw(dm, viewer)); 1722 } else if (isglvis) { 1723 PetscCall(DMPlexView_GLVis(dm, viewer)); 1724 #if defined(PETSC_HAVE_EXODUSII) 1725 } else if (isexodus) { 1726 /* 1727 exodusII requires that all sets be part of exactly one cell set. 1728 If the dm does not have a "Cell Sets" label defined, we create one 1729 with ID 1, containig all cells. 1730 Note that if the Cell Sets label is defined but does not cover all cells, 1731 we may still have a problem. This should probably be checked here or in the viewer; 1732 */ 1733 PetscInt numCS; 1734 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1735 if (!numCS) { 1736 PetscInt cStart, cEnd, c; 1737 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1738 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1739 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1740 } 1741 PetscCall(DMView_PlexExodusII(dm, viewer)); 1742 #endif 1743 } else { 1744 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1745 } 1746 /* Optionally view the partition */ 1747 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1748 if (flg) { 1749 Vec ranks; 1750 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1751 PetscCall(VecView(ranks, viewer)); 1752 PetscCall(VecDestroy(&ranks)); 1753 } 1754 /* Optionally view a label */ 1755 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1756 if (flg) { 1757 DMLabel label; 1758 Vec val; 1759 1760 PetscCall(DMGetLabel(dm, name, &label)); 1761 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1762 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1763 PetscCall(VecView(val, viewer)); 1764 PetscCall(VecDestroy(&val)); 1765 } 1766 PetscFunctionReturn(0); 1767 } 1768 1769 /*@ 1770 DMPlexTopologyView - Saves a DMPlex topology into a file 1771 1772 Collective on DM 1773 1774 Input Parameters: 1775 + dm - The DM whose topology is to be saved 1776 - viewer - The PetscViewer for saving 1777 1778 Level: advanced 1779 1780 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1781 @*/ 1782 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1783 { 1784 PetscBool ishdf5; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1790 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 IS globalPointNumbering; 1797 1798 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1799 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1800 PetscCall(ISDestroy(&globalPointNumbering)); 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1802 #else 1803 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1804 #endif 1805 } 1806 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1807 PetscFunctionReturn(0); 1808 } 1809 1810 /*@ 1811 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1812 1813 Collective on DM 1814 1815 Input Parameters: 1816 + dm - The DM whose coordinates are to be saved 1817 - viewer - The PetscViewer for saving 1818 1819 Level: advanced 1820 1821 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1822 @*/ 1823 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1824 { 1825 PetscBool ishdf5; 1826 1827 PetscFunctionBegin; 1828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1829 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1830 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1831 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1832 if (ishdf5) { 1833 #if defined(PETSC_HAVE_HDF5) 1834 PetscViewerFormat format; 1835 PetscCall(PetscViewerGetFormat(viewer, &format)); 1836 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1837 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1838 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1839 #else 1840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1841 #endif 1842 } 1843 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1844 PetscFunctionReturn(0); 1845 } 1846 1847 /*@ 1848 DMPlexLabelsView - Saves DMPlex labels into a file 1849 1850 Collective on DM 1851 1852 Input Parameters: 1853 + dm - The DM whose labels are to be saved 1854 - viewer - The PetscViewer for saving 1855 1856 Level: advanced 1857 1858 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1859 @*/ 1860 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1861 { 1862 PetscBool ishdf5; 1863 1864 PetscFunctionBegin; 1865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1866 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1867 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1868 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1869 if (ishdf5) { 1870 #if defined(PETSC_HAVE_HDF5) 1871 IS globalPointNumbering; 1872 PetscViewerFormat format; 1873 1874 PetscCall(PetscViewerGetFormat(viewer, &format)); 1875 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1876 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1877 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1878 PetscCall(ISDestroy(&globalPointNumbering)); 1879 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1880 #else 1881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1882 #endif 1883 } 1884 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1885 PetscFunctionReturn(0); 1886 } 1887 1888 /*@ 1889 DMPlexSectionView - Saves a section associated with a DMPlex 1890 1891 Collective on DM 1892 1893 Input Parameters: 1894 + dm - The DM that contains the topology on which the section to be saved is defined 1895 . viewer - The PetscViewer for saving 1896 - sectiondm - The DM that contains the section to be saved 1897 1898 Level: advanced 1899 1900 Notes: 1901 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. 1902 1903 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. 1904 1905 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1906 @*/ 1907 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1908 { 1909 PetscBool ishdf5; 1910 1911 PetscFunctionBegin; 1912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1913 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1914 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1916 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1917 if (ishdf5) { 1918 #if defined(PETSC_HAVE_HDF5) 1919 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1920 #else 1921 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1922 #endif 1923 } 1924 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@ 1929 DMPlexGlobalVectorView - Saves a global vector 1930 1931 Collective on DM 1932 1933 Input Parameters: 1934 + dm - The DM that represents the topology 1935 . viewer - The PetscViewer to save data with 1936 . sectiondm - The DM that contains the global section on which vec is defined 1937 - vec - The global vector to be saved 1938 1939 Level: advanced 1940 1941 Notes: 1942 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. 1943 1944 Typical calling sequence 1945 $ DMCreate(PETSC_COMM_WORLD, &dm); 1946 $ DMSetType(dm, DMPLEX); 1947 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1948 $ DMClone(dm, §iondm); 1949 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1950 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1951 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1952 $ PetscSectionSetChart(section, pStart, pEnd); 1953 $ PetscSectionSetUp(section); 1954 $ DMSetLocalSection(sectiondm, section); 1955 $ PetscSectionDestroy(§ion); 1956 $ DMGetGlobalVector(sectiondm, &vec); 1957 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1958 $ DMPlexTopologyView(dm, viewer); 1959 $ DMPlexSectionView(dm, viewer, sectiondm); 1960 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1961 $ DMRestoreGlobalVector(sectiondm, &vec); 1962 $ DMDestroy(§iondm); 1963 $ DMDestroy(&dm); 1964 1965 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1966 @*/ 1967 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1968 { 1969 PetscBool ishdf5; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1975 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1976 /* Check consistency */ 1977 { 1978 PetscSection section; 1979 PetscBool includesConstraints; 1980 PetscInt m, m1; 1981 1982 PetscCall(VecGetLocalSize(vec, &m1)); 1983 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1984 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1985 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1986 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1987 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1988 } 1989 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1990 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1991 if (ishdf5) { 1992 #if defined(PETSC_HAVE_HDF5) 1993 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1999 PetscFunctionReturn(0); 2000 } 2001 2002 /*@ 2003 DMPlexLocalVectorView - Saves a local vector 2004 2005 Collective on DM 2006 2007 Input Parameters: 2008 + dm - The DM that represents the topology 2009 . viewer - The PetscViewer to save data with 2010 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2011 - vec - The local vector to be saved 2012 2013 Level: advanced 2014 2015 Notes: 2016 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. 2017 2018 Typical calling sequence 2019 $ DMCreate(PETSC_COMM_WORLD, &dm); 2020 $ DMSetType(dm, DMPLEX); 2021 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2022 $ DMClone(dm, §iondm); 2023 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2024 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2025 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2026 $ PetscSectionSetChart(section, pStart, pEnd); 2027 $ PetscSectionSetUp(section); 2028 $ DMSetLocalSection(sectiondm, section); 2029 $ DMGetLocalVector(sectiondm, &vec); 2030 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 $ DMPlexTopologyView(dm, viewer); 2032 $ DMPlexSectionView(dm, viewer, sectiondm); 2033 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2034 $ DMRestoreLocalVector(sectiondm, &vec); 2035 $ DMDestroy(§iondm); 2036 $ DMDestroy(&dm); 2037 2038 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2039 @*/ 2040 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2072 PetscFunctionReturn(0); 2073 } 2074 2075 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2076 { 2077 PetscBool ishdf5; 2078 2079 PetscFunctionBegin; 2080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2081 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2082 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2088 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2089 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2090 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2091 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2092 PetscFunctionReturn(0); 2093 #else 2094 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2095 #endif 2096 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2097 } 2098 2099 /*@ 2100 DMPlexTopologyLoad - Loads a topology into a DMPlex 2101 2102 Collective on DM 2103 2104 Input Parameters: 2105 + dm - The DM into which the topology is loaded 2106 - viewer - The PetscViewer for the saved topology 2107 2108 Output Parameters: 2109 . 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 2110 2111 Level: advanced 2112 2113 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2114 @*/ 2115 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2123 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2124 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2125 if (ishdf5) { 2126 #if defined(PETSC_HAVE_HDF5) 2127 PetscViewerFormat format; 2128 PetscCall(PetscViewerGetFormat(viewer, &format)); 2129 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2130 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2131 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2132 #else 2133 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2134 #endif 2135 } 2136 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2137 PetscFunctionReturn(0); 2138 } 2139 2140 /*@ 2141 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2142 2143 Collective on DM 2144 2145 Input Parameters: 2146 + dm - The DM into which the coordinates are loaded 2147 . viewer - The PetscViewer for the saved coordinates 2148 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2149 2150 Level: advanced 2151 2152 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2153 @*/ 2154 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2155 { 2156 PetscBool ishdf5; 2157 2158 PetscFunctionBegin; 2159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2160 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2161 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2162 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsLoad - Loads labels into a DMPlex 2181 2182 Collective on DM 2183 2184 Input Parameters: 2185 + dm - The DM into which the labels are loaded 2186 . viewer - The PetscViewer for the saved labels 2187 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2188 2189 Level: advanced 2190 2191 Notes: 2192 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2193 2194 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2195 @*/ 2196 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2197 { 2198 PetscBool ishdf5; 2199 2200 PetscFunctionBegin; 2201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2203 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscViewerFormat format; 2209 2210 PetscCall(PetscViewerGetFormat(viewer, &format)); 2211 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2212 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2213 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2214 #else 2215 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2216 #endif 2217 } 2218 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@ 2223 DMPlexSectionLoad - Loads section into a DMPlex 2224 2225 Collective on DM 2226 2227 Input Parameters: 2228 + dm - The DM that represents the topology 2229 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2230 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2231 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2232 2233 Output Parameters 2234 + 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) 2235 - 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) 2236 2237 Level: advanced 2238 2239 Notes: 2240 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. 2241 2242 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. 2243 2244 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. 2245 2246 Example using 2 processes: 2247 $ NX (number of points on dm): 4 2248 $ sectionA : the on-disk section 2249 $ vecA : a vector associated with sectionA 2250 $ sectionB : sectiondm's local section constructed in this function 2251 $ vecB (local) : a vector associated with sectiondm's local section 2252 $ vecB (global) : a vector associated with sectiondm's global section 2253 $ 2254 $ rank 0 rank 1 2255 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2256 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2257 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2258 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2259 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2260 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2261 $ sectionB->atlasDof : 1 0 1 | 1 3 2262 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2263 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2264 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2265 $ 2266 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2267 2268 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2269 @*/ 2270 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2279 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2280 if (localDofSF) PetscValidPointer(localDofSF, 6); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2296 2297 Collective on DM 2298 2299 Input Parameters: 2300 + dm - The DM that represents the topology 2301 . viewer - The PetscViewer that represents the on-disk vector data 2302 . sectiondm - The DM that contains the global section on which vec is defined 2303 . sf - The SF that migrates the on-disk vector data into vec 2304 - vec - The global vector to set values of 2305 2306 Level: advanced 2307 2308 Notes: 2309 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. 2310 2311 Typical calling sequence 2312 $ DMCreate(PETSC_COMM_WORLD, &dm); 2313 $ DMSetType(dm, DMPLEX); 2314 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2316 $ DMClone(dm, §iondm); 2317 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2319 $ DMGetGlobalVector(sectiondm, &vec); 2320 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2322 $ DMRestoreGlobalVector(sectiondm, &vec); 2323 $ PetscSFDestroy(&gsf); 2324 $ PetscSFDestroy(&sfX); 2325 $ DMDestroy(§iondm); 2326 $ DMDestroy(&dm); 2327 2328 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2329 @*/ 2330 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2331 { 2332 PetscBool ishdf5; 2333 2334 PetscFunctionBegin; 2335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2336 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2337 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2338 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2339 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2340 /* Check consistency */ 2341 { 2342 PetscSection section; 2343 PetscBool includesConstraints; 2344 PetscInt m, m1; 2345 2346 PetscCall(VecGetLocalSize(vec, &m1)); 2347 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2348 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2349 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2350 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2351 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2352 } 2353 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2354 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2355 if (ishdf5) { 2356 #if defined(PETSC_HAVE_HDF5) 2357 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2358 #else 2359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2360 #endif 2361 } 2362 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2368 2369 Collective on DM 2370 2371 Input Parameters: 2372 + dm - The DM that represents the topology 2373 . viewer - The PetscViewer that represents the on-disk vector data 2374 . sectiondm - The DM that contains the local section on which vec is defined 2375 . sf - The SF that migrates the on-disk vector data into vec 2376 - vec - The local vector to set values of 2377 2378 Level: advanced 2379 2380 Notes: 2381 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. 2382 2383 Typical calling sequence 2384 $ DMCreate(PETSC_COMM_WORLD, &dm); 2385 $ DMSetType(dm, DMPLEX); 2386 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2387 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2388 $ DMClone(dm, §iondm); 2389 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2391 $ DMGetLocalVector(sectiondm, &vec); 2392 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2393 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2394 $ DMRestoreLocalVector(sectiondm, &vec); 2395 $ PetscSFDestroy(&lsf); 2396 $ PetscSFDestroy(&sfX); 2397 $ DMDestroy(§iondm); 2398 $ DMDestroy(&dm); 2399 2400 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2401 @*/ 2402 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2403 { 2404 PetscBool ishdf5; 2405 2406 PetscFunctionBegin; 2407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2408 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2409 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2410 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2411 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2412 /* Check consistency */ 2413 { 2414 PetscSection section; 2415 PetscBool includesConstraints; 2416 PetscInt m, m1; 2417 2418 PetscCall(VecGetLocalSize(vec, &m1)); 2419 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2420 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2421 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2422 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2423 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2424 } 2425 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2426 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2427 if (ishdf5) { 2428 #if defined(PETSC_HAVE_HDF5) 2429 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2435 PetscFunctionReturn(0); 2436 } 2437 2438 PetscErrorCode DMDestroy_Plex(DM dm) 2439 { 2440 DM_Plex *mesh = (DM_Plex*) dm->data; 2441 2442 PetscFunctionBegin; 2443 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2444 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2445 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2446 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderGetDefault_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexReorderSetDefault_C", NULL)); 2454 if (--mesh->refct > 0) PetscFunctionReturn(0); 2455 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2456 PetscCall(PetscFree(mesh->cones)); 2457 PetscCall(PetscFree(mesh->coneOrientations)); 2458 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2459 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2460 PetscCall(PetscFree(mesh->supports)); 2461 PetscCall(PetscFree(mesh->facesTmp)); 2462 PetscCall(PetscFree(mesh->tetgenOpts)); 2463 PetscCall(PetscFree(mesh->triangleOpts)); 2464 PetscCall(PetscFree(mesh->transformType)); 2465 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2466 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2467 PetscCall(ISDestroy(&mesh->subpointIS)); 2468 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2469 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2470 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2471 PetscCall(ISDestroy(&mesh->anchorIS)); 2472 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2473 PetscCall(PetscFree(mesh->parents)); 2474 PetscCall(PetscFree(mesh->childIDs)); 2475 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2476 PetscCall(PetscFree(mesh->children)); 2477 PetscCall(DMDestroy(&mesh->referenceTree)); 2478 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2479 PetscCall(PetscFree(mesh->neighbors)); 2480 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2481 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2482 PetscCall(PetscFree(mesh)); 2483 PetscFunctionReturn(0); 2484 } 2485 2486 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2487 { 2488 PetscSection sectionGlobal; 2489 PetscInt bs = -1, mbs; 2490 PetscInt localSize, localStart = 0; 2491 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2492 MatType mtype; 2493 ISLocalToGlobalMapping ltog; 2494 2495 PetscFunctionBegin; 2496 PetscCall(MatInitializePackage()); 2497 mtype = dm->mattype; 2498 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2499 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2500 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2501 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2502 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2503 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2504 PetscCall(MatSetType(*J, mtype)); 2505 PetscCall(MatSetFromOptions(*J)); 2506 PetscCall(MatGetBlockSize(*J, &mbs)); 2507 if (mbs > 1) bs = mbs; 2508 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2509 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2510 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2511 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2512 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2513 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2514 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2515 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2516 if (!isShell) { 2517 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2518 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2519 PetscInt pStart, pEnd, p, dof, cdof; 2520 2521 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2522 2523 PetscCall(PetscCalloc1(localSize, &pblocks)); 2524 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2525 for (p = pStart; p < pEnd; ++p) { 2526 PetscInt bdof, offset; 2527 2528 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2529 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2530 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2531 for (PetscInt i=0; i < dof - cdof; i++) 2532 pblocks[offset - localStart + i] = dof - cdof; 2533 dof = dof < 0 ? -(dof+1) : dof; 2534 bdof = cdof && (dof-cdof) ? 1 : dof; 2535 if (dof) { 2536 if (bs < 0) {bs = bdof;} 2537 else if (bs != bdof) {bs = 1;} 2538 } 2539 } 2540 /* Must have same blocksize on all procs (some might have no points) */ 2541 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2542 bsLocal[1] = bs; 2543 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2544 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2545 else bs = bsMinMax[0]; 2546 bs = PetscMax(1,bs); 2547 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2548 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2549 PetscCall(MatSetBlockSize(*J, bs)); 2550 PetscCall(MatSetUp(*J)); 2551 } else { 2552 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2553 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2554 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2555 } 2556 { // Consolidate blocks 2557 PetscInt nblocks = 0; 2558 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2559 if (pblocks[i] == 0) continue; 2560 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2561 for (PetscInt j=1; j<pblocks[i]; j++) { 2562 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]); 2563 } 2564 } 2565 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2566 } 2567 PetscCall(PetscFree(pblocks)); 2568 } 2569 PetscCall(MatSetDM(*J, dm)); 2570 PetscFunctionReturn(0); 2571 } 2572 2573 /*@ 2574 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2575 2576 Not collective 2577 2578 Input Parameter: 2579 . mesh - The DMPlex 2580 2581 Output Parameters: 2582 . subsection - The subdomain section 2583 2584 Level: developer 2585 2586 .seealso: 2587 @*/ 2588 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2589 { 2590 DM_Plex *mesh = (DM_Plex*) dm->data; 2591 2592 PetscFunctionBegin; 2593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2594 if (!mesh->subdomainSection) { 2595 PetscSection section; 2596 PetscSF sf; 2597 2598 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2599 PetscCall(DMGetLocalSection(dm,§ion)); 2600 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2601 PetscCall(PetscSFDestroy(&sf)); 2602 } 2603 *subsection = mesh->subdomainSection; 2604 PetscFunctionReturn(0); 2605 } 2606 2607 /*@ 2608 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2609 2610 Not collective 2611 2612 Input Parameter: 2613 . mesh - The DMPlex 2614 2615 Output Parameters: 2616 + pStart - The first mesh point 2617 - pEnd - The upper bound for mesh points 2618 2619 Level: beginner 2620 2621 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2622 @*/ 2623 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2624 { 2625 DM_Plex *mesh = (DM_Plex*) dm->data; 2626 2627 PetscFunctionBegin; 2628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2629 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2630 PetscFunctionReturn(0); 2631 } 2632 2633 /*@ 2634 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2635 2636 Not collective 2637 2638 Input Parameters: 2639 + mesh - The DMPlex 2640 . pStart - The first mesh point 2641 - pEnd - The upper bound for mesh points 2642 2643 Output Parameters: 2644 2645 Level: beginner 2646 2647 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2648 @*/ 2649 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2650 { 2651 DM_Plex *mesh = (DM_Plex*) dm->data; 2652 2653 PetscFunctionBegin; 2654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2655 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2656 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2657 PetscFunctionReturn(0); 2658 } 2659 2660 /*@ 2661 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2662 2663 Not collective 2664 2665 Input Parameters: 2666 + mesh - The DMPlex 2667 - p - The point, which must lie in the chart set with DMPlexSetChart() 2668 2669 Output Parameter: 2670 . size - The cone size for point p 2671 2672 Level: beginner 2673 2674 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2675 @*/ 2676 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2677 { 2678 DM_Plex *mesh = (DM_Plex*) dm->data; 2679 2680 PetscFunctionBegin; 2681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2682 PetscValidIntPointer(size, 3); 2683 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2684 PetscFunctionReturn(0); 2685 } 2686 2687 /*@ 2688 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2689 2690 Not collective 2691 2692 Input Parameters: 2693 + mesh - The DMPlex 2694 . p - The point, which must lie in the chart set with DMPlexSetChart() 2695 - size - The cone size for point p 2696 2697 Output Parameter: 2698 2699 Note: 2700 This should be called after DMPlexSetChart(). 2701 2702 Level: beginner 2703 2704 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2705 @*/ 2706 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2707 { 2708 DM_Plex *mesh = (DM_Plex*) dm->data; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2713 PetscFunctionReturn(0); 2714 } 2715 2716 /*@ 2717 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2718 2719 Not collective 2720 2721 Input Parameters: 2722 + mesh - The DMPlex 2723 . p - The point, which must lie in the chart set with DMPlexSetChart() 2724 - size - The additional cone size for point p 2725 2726 Output Parameter: 2727 2728 Note: 2729 This should be called after DMPlexSetChart(). 2730 2731 Level: beginner 2732 2733 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2734 @*/ 2735 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2736 { 2737 DM_Plex *mesh = (DM_Plex*) dm->data; 2738 PetscFunctionBegin; 2739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2740 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2741 PetscFunctionReturn(0); 2742 } 2743 2744 /*@C 2745 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2746 2747 Not collective 2748 2749 Input Parameters: 2750 + dm - The DMPlex 2751 - p - The point, which must lie in the chart set with DMPlexSetChart() 2752 2753 Output Parameter: 2754 . cone - An array of points which are on the in-edges for point p 2755 2756 Level: beginner 2757 2758 Fortran Notes: 2759 Since it returns an array, this routine is only available in Fortran 90, and you must 2760 include petsc.h90 in your code. 2761 You must also call DMPlexRestoreCone() after you finish using the returned array. 2762 DMPlexRestoreCone() is not needed/available in C. 2763 2764 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2765 @*/ 2766 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2767 { 2768 DM_Plex *mesh = (DM_Plex*) dm->data; 2769 PetscInt off; 2770 2771 PetscFunctionBegin; 2772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2773 PetscValidPointer(cone, 3); 2774 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2775 *cone = &mesh->cones[off]; 2776 PetscFunctionReturn(0); 2777 } 2778 2779 /*@C 2780 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2781 2782 Not collective 2783 2784 Input Parameters: 2785 + dm - The DMPlex 2786 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2787 2788 Output Parameters: 2789 + pConesSection - PetscSection describing the layout of pCones 2790 - pCones - An array of points which are on the in-edges for the point set p 2791 2792 Level: intermediate 2793 2794 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2795 @*/ 2796 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2797 { 2798 PetscSection cs, newcs; 2799 PetscInt *cones; 2800 PetscInt *newarr=NULL; 2801 PetscInt n; 2802 2803 PetscFunctionBegin; 2804 PetscCall(DMPlexGetCones(dm, &cones)); 2805 PetscCall(DMPlexGetConeSection(dm, &cs)); 2806 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2807 if (pConesSection) *pConesSection = newcs; 2808 if (pCones) { 2809 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2810 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2811 } 2812 PetscFunctionReturn(0); 2813 } 2814 2815 /*@ 2816 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2817 2818 Not collective 2819 2820 Input Parameters: 2821 + dm - The DMPlex 2822 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2823 2824 Output Parameter: 2825 . expandedPoints - An array of vertices recursively expanded from input points 2826 2827 Level: advanced 2828 2829 Notes: 2830 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2831 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2832 2833 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2834 @*/ 2835 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2836 { 2837 IS *expandedPointsAll; 2838 PetscInt depth; 2839 2840 PetscFunctionBegin; 2841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2842 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2843 PetscValidPointer(expandedPoints, 3); 2844 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2845 *expandedPoints = expandedPointsAll[0]; 2846 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2847 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2848 PetscFunctionReturn(0); 2849 } 2850 2851 /*@ 2852 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). 2853 2854 Not collective 2855 2856 Input Parameters: 2857 + dm - The DMPlex 2858 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2859 2860 Output Parameters: 2861 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2862 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2863 - sections - (optional) An array of sections which describe mappings from points to their cone points 2864 2865 Level: advanced 2866 2867 Notes: 2868 Like DMPlexGetConeTuple() but recursive. 2869 2870 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. 2871 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2872 2873 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: 2874 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2875 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2876 2877 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2878 @*/ 2879 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2880 { 2881 const PetscInt *arr0=NULL, *cone=NULL; 2882 PetscInt *arr=NULL, *newarr=NULL; 2883 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2884 IS *expandedPoints_; 2885 PetscSection *sections_; 2886 2887 PetscFunctionBegin; 2888 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2889 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2890 if (depth) PetscValidIntPointer(depth, 3); 2891 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2892 if (sections) PetscValidPointer(sections, 5); 2893 PetscCall(ISGetLocalSize(points, &n)); 2894 PetscCall(ISGetIndices(points, &arr0)); 2895 PetscCall(DMPlexGetDepth(dm, &depth_)); 2896 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2897 PetscCall(PetscCalloc1(depth_, §ions_)); 2898 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2899 for (d=depth_-1; d>=0; d--) { 2900 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2901 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2902 for (i=0; i<n; i++) { 2903 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2904 if (arr[i] >= start && arr[i] < end) { 2905 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2906 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2907 } else { 2908 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2909 } 2910 } 2911 PetscCall(PetscSectionSetUp(sections_[d])); 2912 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2913 PetscCall(PetscMalloc1(newn, &newarr)); 2914 for (i=0; i<n; i++) { 2915 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2916 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2917 if (cn > 1) { 2918 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2919 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2920 } else { 2921 newarr[co] = arr[i]; 2922 } 2923 } 2924 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2925 arr = newarr; 2926 n = newn; 2927 } 2928 PetscCall(ISRestoreIndices(points, &arr0)); 2929 *depth = depth_; 2930 if (expandedPoints) *expandedPoints = expandedPoints_; 2931 else { 2932 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2933 PetscCall(PetscFree(expandedPoints_)); 2934 } 2935 if (sections) *sections = sections_; 2936 else { 2937 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2938 PetscCall(PetscFree(sections_)); 2939 } 2940 PetscFunctionReturn(0); 2941 } 2942 2943 /*@ 2944 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2945 2946 Not collective 2947 2948 Input Parameters: 2949 + dm - The DMPlex 2950 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2951 2952 Output Parameters: 2953 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2954 . expandedPoints - (optional) An array of recursively expanded cones 2955 - sections - (optional) An array of sections which describe mappings from points to their cone points 2956 2957 Level: advanced 2958 2959 Notes: 2960 See DMPlexGetConeRecursive() for details. 2961 2962 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2963 @*/ 2964 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2965 { 2966 PetscInt d, depth_; 2967 2968 PetscFunctionBegin; 2969 PetscCall(DMPlexGetDepth(dm, &depth_)); 2970 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2971 if (depth) *depth = 0; 2972 if (expandedPoints) { 2973 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2974 PetscCall(PetscFree(*expandedPoints)); 2975 } 2976 if (sections) { 2977 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2978 PetscCall(PetscFree(*sections)); 2979 } 2980 PetscFunctionReturn(0); 2981 } 2982 2983 /*@ 2984 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 2985 2986 Not collective 2987 2988 Input Parameters: 2989 + mesh - The DMPlex 2990 . p - The point, which must lie in the chart set with DMPlexSetChart() 2991 - cone - An array of points which are on the in-edges for point p 2992 2993 Output Parameter: 2994 2995 Note: 2996 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2997 2998 Level: beginner 2999 3000 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3001 @*/ 3002 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3003 { 3004 DM_Plex *mesh = (DM_Plex*) dm->data; 3005 PetscInt pStart, pEnd; 3006 PetscInt dof, off, c; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3011 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3012 if (dof) PetscValidIntPointer(cone, 3); 3013 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3014 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); 3015 for (c = 0; c < dof; ++c) { 3016 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); 3017 mesh->cones[off+c] = cone[c]; 3018 } 3019 PetscFunctionReturn(0); 3020 } 3021 3022 /*@C 3023 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3024 3025 Not collective 3026 3027 Input Parameters: 3028 + mesh - The DMPlex 3029 - p - The point, which must lie in the chart set with DMPlexSetChart() 3030 3031 Output Parameter: 3032 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3033 integer giving the prescription for cone traversal. 3034 3035 Level: beginner 3036 3037 Notes: 3038 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3039 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3040 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3041 with the identity. 3042 3043 Fortran Notes: 3044 Since it returns an array, this routine is only available in Fortran 90, and you must 3045 include petsc.h90 in your code. 3046 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3047 DMPlexRestoreConeOrientation() is not needed/available in C. 3048 3049 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3050 @*/ 3051 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3052 { 3053 DM_Plex *mesh = (DM_Plex*) dm->data; 3054 PetscInt off; 3055 3056 PetscFunctionBegin; 3057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3058 if (PetscDefined(USE_DEBUG)) { 3059 PetscInt dof; 3060 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3061 if (dof) PetscValidPointer(coneOrientation, 3); 3062 } 3063 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3064 3065 *coneOrientation = &mesh->coneOrientations[off]; 3066 PetscFunctionReturn(0); 3067 } 3068 3069 /*@ 3070 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3071 3072 Not collective 3073 3074 Input Parameters: 3075 + mesh - The DMPlex 3076 . p - The point, which must lie in the chart set with DMPlexSetChart() 3077 - coneOrientation - An array of orientations 3078 Output Parameter: 3079 3080 Notes: 3081 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3082 3083 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3084 3085 Level: beginner 3086 3087 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3088 @*/ 3089 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3090 { 3091 DM_Plex *mesh = (DM_Plex*) dm->data; 3092 PetscInt pStart, pEnd; 3093 PetscInt dof, off, c; 3094 3095 PetscFunctionBegin; 3096 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3097 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3098 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3099 if (dof) PetscValidIntPointer(coneOrientation, 3); 3100 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3101 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); 3102 for (c = 0; c < dof; ++c) { 3103 PetscInt cdof, o = coneOrientation[c]; 3104 3105 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3106 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); 3107 mesh->coneOrientations[off+c] = o; 3108 } 3109 PetscFunctionReturn(0); 3110 } 3111 3112 /*@ 3113 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3114 3115 Not collective 3116 3117 Input Parameters: 3118 + mesh - The DMPlex 3119 . p - The point, which must lie in the chart set with DMPlexSetChart() 3120 . conePos - The local index in the cone where the point should be put 3121 - conePoint - The mesh point to insert 3122 3123 Level: beginner 3124 3125 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3126 @*/ 3127 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3128 { 3129 DM_Plex *mesh = (DM_Plex*) dm->data; 3130 PetscInt pStart, pEnd; 3131 PetscInt dof, off; 3132 3133 PetscFunctionBegin; 3134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3135 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3136 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); 3137 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); 3138 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3139 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3140 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); 3141 mesh->cones[off+conePos] = conePoint; 3142 PetscFunctionReturn(0); 3143 } 3144 3145 /*@ 3146 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3147 3148 Not collective 3149 3150 Input Parameters: 3151 + mesh - The DMPlex 3152 . p - The point, which must lie in the chart set with DMPlexSetChart() 3153 . conePos - The local index in the cone where the point should be put 3154 - coneOrientation - The point orientation to insert 3155 3156 Level: beginner 3157 3158 Notes: 3159 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3160 3161 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3162 @*/ 3163 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3164 { 3165 DM_Plex *mesh = (DM_Plex*) dm->data; 3166 PetscInt pStart, pEnd; 3167 PetscInt dof, off; 3168 3169 PetscFunctionBegin; 3170 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3171 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3172 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); 3173 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3174 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3175 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); 3176 mesh->coneOrientations[off+conePos] = coneOrientation; 3177 PetscFunctionReturn(0); 3178 } 3179 3180 /*@ 3181 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3182 3183 Not collective 3184 3185 Input Parameters: 3186 + mesh - The DMPlex 3187 - p - The point, which must lie in the chart set with DMPlexSetChart() 3188 3189 Output Parameter: 3190 . size - The support size for point p 3191 3192 Level: beginner 3193 3194 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3195 @*/ 3196 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3197 { 3198 DM_Plex *mesh = (DM_Plex*) dm->data; 3199 3200 PetscFunctionBegin; 3201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3202 PetscValidIntPointer(size, 3); 3203 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3204 PetscFunctionReturn(0); 3205 } 3206 3207 /*@ 3208 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3209 3210 Not collective 3211 3212 Input Parameters: 3213 + mesh - The DMPlex 3214 . p - The point, which must lie in the chart set with DMPlexSetChart() 3215 - size - The support size for point p 3216 3217 Output Parameter: 3218 3219 Note: 3220 This should be called after DMPlexSetChart(). 3221 3222 Level: beginner 3223 3224 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3225 @*/ 3226 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3227 { 3228 DM_Plex *mesh = (DM_Plex*) dm->data; 3229 3230 PetscFunctionBegin; 3231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3232 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3233 PetscFunctionReturn(0); 3234 } 3235 3236 /*@C 3237 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3238 3239 Not collective 3240 3241 Input Parameters: 3242 + mesh - The DMPlex 3243 - p - The point, which must lie in the chart set with DMPlexSetChart() 3244 3245 Output Parameter: 3246 . support - An array of points which are on the out-edges for point p 3247 3248 Level: beginner 3249 3250 Fortran Notes: 3251 Since it returns an array, this routine is only available in Fortran 90, and you must 3252 include petsc.h90 in your code. 3253 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3254 DMPlexRestoreSupport() is not needed/available in C. 3255 3256 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3257 @*/ 3258 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3259 { 3260 DM_Plex *mesh = (DM_Plex*) dm->data; 3261 PetscInt off; 3262 3263 PetscFunctionBegin; 3264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3265 PetscValidPointer(support, 3); 3266 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3267 *support = &mesh->supports[off]; 3268 PetscFunctionReturn(0); 3269 } 3270 3271 /*@ 3272 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3273 3274 Not collective 3275 3276 Input Parameters: 3277 + mesh - The DMPlex 3278 . p - The point, which must lie in the chart set with DMPlexSetChart() 3279 - support - An array of points which are on the out-edges for point p 3280 3281 Output Parameter: 3282 3283 Note: 3284 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3285 3286 Level: beginner 3287 3288 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3289 @*/ 3290 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3291 { 3292 DM_Plex *mesh = (DM_Plex*) dm->data; 3293 PetscInt pStart, pEnd; 3294 PetscInt dof, off, c; 3295 3296 PetscFunctionBegin; 3297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3298 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3299 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3300 if (dof) PetscValidIntPointer(support, 3); 3301 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3302 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); 3303 for (c = 0; c < dof; ++c) { 3304 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); 3305 mesh->supports[off+c] = support[c]; 3306 } 3307 PetscFunctionReturn(0); 3308 } 3309 3310 /*@ 3311 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3312 3313 Not collective 3314 3315 Input Parameters: 3316 + mesh - The DMPlex 3317 . p - The point, which must lie in the chart set with DMPlexSetChart() 3318 . supportPos - The local index in the cone where the point should be put 3319 - supportPoint - The mesh point to insert 3320 3321 Level: beginner 3322 3323 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3324 @*/ 3325 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3326 { 3327 DM_Plex *mesh = (DM_Plex*) dm->data; 3328 PetscInt pStart, pEnd; 3329 PetscInt dof, off; 3330 3331 PetscFunctionBegin; 3332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3333 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3334 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3335 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3336 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); 3337 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); 3338 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); 3339 mesh->supports[off+supportPos] = supportPoint; 3340 PetscFunctionReturn(0); 3341 } 3342 3343 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3344 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3345 { 3346 switch (ct) { 3347 case DM_POLYTOPE_SEGMENT: 3348 if (o == -1) return -2; 3349 break; 3350 case DM_POLYTOPE_TRIANGLE: 3351 if (o == -3) return -1; 3352 if (o == -2) return -3; 3353 if (o == -1) return -2; 3354 break; 3355 case DM_POLYTOPE_QUADRILATERAL: 3356 if (o == -4) return -2; 3357 if (o == -3) return -1; 3358 if (o == -2) return -4; 3359 if (o == -1) return -3; 3360 break; 3361 default: return o; 3362 } 3363 return o; 3364 } 3365 3366 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3367 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3368 { 3369 switch (ct) { 3370 case DM_POLYTOPE_SEGMENT: 3371 if ((o == -2) || (o == 1)) return -1; 3372 if (o == -1) return 0; 3373 break; 3374 case DM_POLYTOPE_TRIANGLE: 3375 if (o == -3) return -2; 3376 if (o == -2) return -1; 3377 if (o == -1) return -3; 3378 break; 3379 case DM_POLYTOPE_QUADRILATERAL: 3380 if (o == -4) return -2; 3381 if (o == -3) return -1; 3382 if (o == -2) return -4; 3383 if (o == -1) return -3; 3384 break; 3385 default: return o; 3386 } 3387 return o; 3388 } 3389 3390 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3391 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3392 { 3393 PetscInt pStart, pEnd, p; 3394 3395 PetscFunctionBegin; 3396 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3397 for (p = pStart; p < pEnd; ++p) { 3398 const PetscInt *cone, *ornt; 3399 PetscInt coneSize, c; 3400 3401 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3402 PetscCall(DMPlexGetCone(dm, p, &cone)); 3403 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3404 for (c = 0; c < coneSize; ++c) { 3405 DMPolytopeType ct; 3406 const PetscInt o = ornt[c]; 3407 3408 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3409 switch (ct) { 3410 case DM_POLYTOPE_SEGMENT: 3411 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3412 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3413 break; 3414 case DM_POLYTOPE_TRIANGLE: 3415 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3416 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3417 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3418 break; 3419 case DM_POLYTOPE_QUADRILATERAL: 3420 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3421 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3422 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3423 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3424 break; 3425 default: break; 3426 } 3427 } 3428 } 3429 PetscFunctionReturn(0); 3430 } 3431 3432 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3433 { 3434 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3435 PetscInt *closure; 3436 const PetscInt *tmp = NULL, *tmpO = NULL; 3437 PetscInt off = 0, tmpSize, t; 3438 3439 PetscFunctionBeginHot; 3440 if (ornt) { 3441 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3442 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3443 } 3444 if (*points) { 3445 closure = *points; 3446 } else { 3447 PetscInt maxConeSize, maxSupportSize; 3448 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3449 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3450 } 3451 if (useCone) { 3452 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3453 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3454 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3455 } else { 3456 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3457 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3458 } 3459 if (ct == DM_POLYTOPE_UNKNOWN) { 3460 closure[off++] = p; 3461 closure[off++] = 0; 3462 for (t = 0; t < tmpSize; ++t) { 3463 closure[off++] = tmp[t]; 3464 closure[off++] = tmpO ? tmpO[t] : 0; 3465 } 3466 } else { 3467 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3468 3469 /* We assume that cells with a valid type have faces with a valid type */ 3470 closure[off++] = p; 3471 closure[off++] = ornt; 3472 for (t = 0; t < tmpSize; ++t) { 3473 DMPolytopeType ft; 3474 3475 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3476 closure[off++] = tmp[arr[t]]; 3477 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3478 } 3479 } 3480 if (numPoints) *numPoints = tmpSize+1; 3481 if (points) *points = closure; 3482 PetscFunctionReturn(0); 3483 } 3484 3485 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3486 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3487 { 3488 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3489 const PetscInt *cone, *ornt; 3490 PetscInt *pts, *closure = NULL; 3491 DMPolytopeType ft; 3492 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3493 PetscInt dim, coneSize, c, d, clSize, cl; 3494 3495 PetscFunctionBeginHot; 3496 PetscCall(DMGetDimension(dm, &dim)); 3497 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3498 PetscCall(DMPlexGetCone(dm, point, &cone)); 3499 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3500 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3501 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3502 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3503 maxSize = PetscMax(coneSeries, supportSeries); 3504 if (*points) {pts = *points;} 3505 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3506 c = 0; 3507 pts[c++] = point; 3508 pts[c++] = o; 3509 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3510 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3511 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3512 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3513 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3514 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3515 for (d = 2; d < coneSize; ++d) { 3516 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3517 pts[c++] = cone[arr[d*2+0]]; 3518 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3519 } 3520 if (dim >= 3) { 3521 for (d = 2; d < coneSize; ++d) { 3522 const PetscInt fpoint = cone[arr[d*2+0]]; 3523 const PetscInt *fcone, *fornt; 3524 PetscInt fconeSize, fc, i; 3525 3526 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3527 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3528 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3529 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3530 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3531 for (fc = 0; fc < fconeSize; ++fc) { 3532 const PetscInt cp = fcone[farr[fc*2+0]]; 3533 const PetscInt co = farr[fc*2+1]; 3534 3535 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3536 if (i == c) { 3537 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3538 pts[c++] = cp; 3539 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3540 } 3541 } 3542 } 3543 } 3544 *numPoints = c/2; 3545 *points = pts; 3546 PetscFunctionReturn(0); 3547 } 3548 3549 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3550 { 3551 DMPolytopeType ct; 3552 PetscInt *closure, *fifo; 3553 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3554 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3555 PetscInt depth, maxSize; 3556 3557 PetscFunctionBeginHot; 3558 PetscCall(DMPlexGetDepth(dm, &depth)); 3559 if (depth == 1) { 3560 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3561 PetscFunctionReturn(0); 3562 } 3563 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3564 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3565 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3566 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3567 PetscFunctionReturn(0); 3568 } 3569 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3570 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3571 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3572 maxSize = PetscMax(coneSeries, supportSeries); 3573 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3574 if (*points) {closure = *points;} 3575 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3576 closure[closureSize++] = p; 3577 closure[closureSize++] = ornt; 3578 fifo[fifoSize++] = p; 3579 fifo[fifoSize++] = ornt; 3580 fifo[fifoSize++] = ct; 3581 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3582 while (fifoSize - fifoStart) { 3583 const PetscInt q = fifo[fifoStart++]; 3584 const PetscInt o = fifo[fifoStart++]; 3585 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3586 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3587 const PetscInt *tmp, *tmpO; 3588 PetscInt tmpSize, t; 3589 3590 if (PetscDefined(USE_DEBUG)) { 3591 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3592 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); 3593 } 3594 if (useCone) { 3595 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3596 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3597 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3598 } else { 3599 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3600 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3601 tmpO = NULL; 3602 } 3603 for (t = 0; t < tmpSize; ++t) { 3604 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3605 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3606 const PetscInt cp = tmp[ip]; 3607 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3608 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3609 PetscInt c; 3610 3611 /* Check for duplicate */ 3612 for (c = 0; c < closureSize; c += 2) { 3613 if (closure[c] == cp) break; 3614 } 3615 if (c == closureSize) { 3616 closure[closureSize++] = cp; 3617 closure[closureSize++] = co; 3618 fifo[fifoSize++] = cp; 3619 fifo[fifoSize++] = co; 3620 fifo[fifoSize++] = ct; 3621 } 3622 } 3623 } 3624 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3625 if (numPoints) *numPoints = closureSize/2; 3626 if (points) *points = closure; 3627 PetscFunctionReturn(0); 3628 } 3629 3630 /*@C 3631 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3632 3633 Not collective 3634 3635 Input Parameters: 3636 + dm - The DMPlex 3637 . p - The mesh point 3638 - useCone - PETSC_TRUE for the closure, otherwise return the star 3639 3640 Input/Output Parameter: 3641 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3642 if NULL on input, internal storage will be returned, otherwise the provided array is used 3643 3644 Output Parameter: 3645 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3646 3647 Note: 3648 If using internal storage (points is NULL on input), each call overwrites the last output. 3649 3650 Fortran Notes: 3651 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3652 3653 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3654 3655 Level: beginner 3656 3657 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3658 @*/ 3659 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3660 { 3661 PetscFunctionBeginHot; 3662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3663 if (numPoints) PetscValidIntPointer(numPoints, 4); 3664 if (points) PetscValidPointer(points, 5); 3665 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3666 PetscFunctionReturn(0); 3667 } 3668 3669 /*@C 3670 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3671 3672 Not collective 3673 3674 Input Parameters: 3675 + dm - The DMPlex 3676 . p - The mesh point 3677 . useCone - PETSC_TRUE for the closure, otherwise return the star 3678 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3679 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3680 3681 Note: 3682 If not using internal storage (points is not NULL on input), this call is unnecessary 3683 3684 Fortran Notes: 3685 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3686 3687 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3688 3689 Level: beginner 3690 3691 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3692 @*/ 3693 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3694 { 3695 PetscFunctionBeginHot; 3696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3697 if (numPoints) *numPoints = 0; 3698 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3699 PetscFunctionReturn(0); 3700 } 3701 3702 /*@ 3703 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3704 3705 Not collective 3706 3707 Input Parameter: 3708 . mesh - The DMPlex 3709 3710 Output Parameters: 3711 + maxConeSize - The maximum number of in-edges 3712 - maxSupportSize - The maximum number of out-edges 3713 3714 Level: beginner 3715 3716 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3717 @*/ 3718 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3719 { 3720 DM_Plex *mesh = (DM_Plex*) dm->data; 3721 3722 PetscFunctionBegin; 3723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3724 if (maxConeSize) { 3725 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3726 } 3727 if (maxSupportSize) { 3728 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3729 } 3730 PetscFunctionReturn(0); 3731 } 3732 3733 PetscErrorCode DMSetUp_Plex(DM dm) 3734 { 3735 DM_Plex *mesh = (DM_Plex*) dm->data; 3736 PetscInt size, maxSupportSize; 3737 3738 PetscFunctionBegin; 3739 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3740 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3741 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3742 PetscCall(PetscMalloc1(size, &mesh->cones)); 3743 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3744 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3745 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3746 if (maxSupportSize) { 3747 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3748 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3749 PetscCall(PetscMalloc1(size, &mesh->supports)); 3750 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3751 } 3752 PetscFunctionReturn(0); 3753 } 3754 3755 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3756 { 3757 PetscFunctionBegin; 3758 if (subdm) PetscCall(DMClone(dm, subdm)); 3759 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3760 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3761 if (dm->useNatural && dm->sfMigration) { 3762 PetscSF sfMigrationInv,sfNatural; 3763 PetscSection section, sectionSeq; 3764 3765 (*subdm)->sfMigration = dm->sfMigration; 3766 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3767 PetscCall(DMGetLocalSection((*subdm), §ion)); 3768 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3769 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3770 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3771 3772 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3773 (*subdm)->sfNatural = sfNatural; 3774 PetscCall(PetscSectionDestroy(§ionSeq)); 3775 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3776 } 3777 PetscFunctionReturn(0); 3778 } 3779 3780 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3781 { 3782 PetscInt i = 0; 3783 3784 PetscFunctionBegin; 3785 PetscCall(DMClone(dms[0], superdm)); 3786 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3787 (*superdm)->useNatural = PETSC_FALSE; 3788 for (i = 0; i < len; i++) { 3789 if (dms[i]->useNatural && dms[i]->sfMigration) { 3790 PetscSF sfMigrationInv,sfNatural; 3791 PetscSection section, sectionSeq; 3792 3793 (*superdm)->sfMigration = dms[i]->sfMigration; 3794 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3795 (*superdm)->useNatural = PETSC_TRUE; 3796 PetscCall(DMGetLocalSection((*superdm), §ion)); 3797 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3798 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3799 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3800 3801 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3802 (*superdm)->sfNatural = sfNatural; 3803 PetscCall(PetscSectionDestroy(§ionSeq)); 3804 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3805 break; 3806 } 3807 } 3808 PetscFunctionReturn(0); 3809 } 3810 3811 /*@ 3812 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3813 3814 Not collective 3815 3816 Input Parameter: 3817 . mesh - The DMPlex 3818 3819 Output Parameter: 3820 3821 Note: 3822 This should be called after all calls to DMPlexSetCone() 3823 3824 Level: beginner 3825 3826 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3827 @*/ 3828 PetscErrorCode DMPlexSymmetrize(DM dm) 3829 { 3830 DM_Plex *mesh = (DM_Plex*) dm->data; 3831 PetscInt *offsets; 3832 PetscInt supportSize; 3833 PetscInt pStart, pEnd, p; 3834 3835 PetscFunctionBegin; 3836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3837 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3838 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3839 /* Calculate support sizes */ 3840 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3841 for (p = pStart; p < pEnd; ++p) { 3842 PetscInt dof, off, c; 3843 3844 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3845 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3846 for (c = off; c < off+dof; ++c) { 3847 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3848 } 3849 } 3850 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3851 /* Calculate supports */ 3852 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3853 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3854 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3855 for (p = pStart; p < pEnd; ++p) { 3856 PetscInt dof, off, c; 3857 3858 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3859 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3860 for (c = off; c < off+dof; ++c) { 3861 const PetscInt q = mesh->cones[c]; 3862 PetscInt offS; 3863 3864 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3865 3866 mesh->supports[offS+offsets[q]] = p; 3867 ++offsets[q]; 3868 } 3869 } 3870 PetscCall(PetscFree(offsets)); 3871 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3872 PetscFunctionReturn(0); 3873 } 3874 3875 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3876 { 3877 IS stratumIS; 3878 3879 PetscFunctionBegin; 3880 if (pStart >= pEnd) PetscFunctionReturn(0); 3881 if (PetscDefined(USE_DEBUG)) { 3882 PetscInt qStart, qEnd, numLevels, level; 3883 PetscBool overlap = PETSC_FALSE; 3884 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3885 for (level = 0; level < numLevels; level++) { 3886 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3887 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3888 } 3889 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); 3890 } 3891 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3892 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3893 PetscCall(ISDestroy(&stratumIS)); 3894 PetscFunctionReturn(0); 3895 } 3896 3897 /*@ 3898 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3899 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3900 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3901 the DAG. 3902 3903 Collective on dm 3904 3905 Input Parameter: 3906 . mesh - The DMPlex 3907 3908 Output Parameter: 3909 3910 Notes: 3911 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3912 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3913 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3914 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3915 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3916 3917 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3918 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3919 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 3920 to interpolate only that one (e0), so that 3921 $ cone(c0) = {e0, v2} 3922 $ cone(e0) = {v0, v1} 3923 If DMPlexStratify() is run on this mesh, it will give depths 3924 $ depth 0 = {v0, v1, v2} 3925 $ depth 1 = {e0, c0} 3926 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3927 3928 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3929 3930 Level: beginner 3931 3932 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3933 @*/ 3934 PetscErrorCode DMPlexStratify(DM dm) 3935 { 3936 DM_Plex *mesh = (DM_Plex*) dm->data; 3937 DMLabel label; 3938 PetscInt pStart, pEnd, p; 3939 PetscInt numRoots = 0, numLeaves = 0; 3940 3941 PetscFunctionBegin; 3942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3943 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3944 3945 /* Create depth label */ 3946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3947 PetscCall(DMCreateLabel(dm, "depth")); 3948 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3949 3950 { 3951 /* Initialize roots and count leaves */ 3952 PetscInt sMin = PETSC_MAX_INT; 3953 PetscInt sMax = PETSC_MIN_INT; 3954 PetscInt coneSize, supportSize; 3955 3956 for (p = pStart; p < pEnd; ++p) { 3957 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3958 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3959 if (!coneSize && supportSize) { 3960 sMin = PetscMin(p, sMin); 3961 sMax = PetscMax(p, sMax); 3962 ++numRoots; 3963 } else if (!supportSize && coneSize) { 3964 ++numLeaves; 3965 } else if (!supportSize && !coneSize) { 3966 /* Isolated points */ 3967 sMin = PetscMin(p, sMin); 3968 sMax = PetscMax(p, sMax); 3969 } 3970 } 3971 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3972 } 3973 3974 if (numRoots + numLeaves == (pEnd - pStart)) { 3975 PetscInt sMin = PETSC_MAX_INT; 3976 PetscInt sMax = PETSC_MIN_INT; 3977 PetscInt coneSize, supportSize; 3978 3979 for (p = pStart; p < pEnd; ++p) { 3980 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3981 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3982 if (!supportSize && coneSize) { 3983 sMin = PetscMin(p, sMin); 3984 sMax = PetscMax(p, sMax); 3985 } 3986 } 3987 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3988 } else { 3989 PetscInt level = 0; 3990 PetscInt qStart, qEnd, q; 3991 3992 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3993 while (qEnd > qStart) { 3994 PetscInt sMin = PETSC_MAX_INT; 3995 PetscInt sMax = PETSC_MIN_INT; 3996 3997 for (q = qStart; q < qEnd; ++q) { 3998 const PetscInt *support; 3999 PetscInt supportSize, s; 4000 4001 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4002 PetscCall(DMPlexGetSupport(dm, q, &support)); 4003 for (s = 0; s < supportSize; ++s) { 4004 sMin = PetscMin(support[s], sMin); 4005 sMax = PetscMax(support[s], sMax); 4006 } 4007 } 4008 PetscCall(DMLabelGetNumValues(label, &level)); 4009 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4010 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4011 } 4012 } 4013 { /* just in case there is an empty process */ 4014 PetscInt numValues, maxValues = 0, v; 4015 4016 PetscCall(DMLabelGetNumValues(label, &numValues)); 4017 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4018 for (v = numValues; v < maxValues; v++) { 4019 PetscCall(DMLabelAddStratum(label, v)); 4020 } 4021 } 4022 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4023 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4024 PetscFunctionReturn(0); 4025 } 4026 4027 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4028 { 4029 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4030 PetscInt dim, depth, pheight, coneSize; 4031 4032 PetscFunctionBeginHot; 4033 PetscCall(DMGetDimension(dm, &dim)); 4034 PetscCall(DMPlexGetDepth(dm, &depth)); 4035 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4036 pheight = depth - pdepth; 4037 if (depth <= 1) { 4038 switch (pdepth) { 4039 case 0: ct = DM_POLYTOPE_POINT;break; 4040 case 1: 4041 switch (coneSize) { 4042 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4043 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4044 case 4: 4045 switch (dim) { 4046 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4047 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4048 default: break; 4049 } 4050 break; 4051 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4052 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4053 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4054 default: break; 4055 } 4056 } 4057 } else { 4058 if (pdepth == 0) { 4059 ct = DM_POLYTOPE_POINT; 4060 } else if (pheight == 0) { 4061 switch (dim) { 4062 case 1: 4063 switch (coneSize) { 4064 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4065 default: break; 4066 } 4067 break; 4068 case 2: 4069 switch (coneSize) { 4070 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4071 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4072 default: break; 4073 } 4074 break; 4075 case 3: 4076 switch (coneSize) { 4077 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4078 case 5: 4079 { 4080 const PetscInt *cone; 4081 PetscInt faceConeSize; 4082 4083 PetscCall(DMPlexGetCone(dm, p, &cone)); 4084 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4085 switch (faceConeSize) { 4086 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4087 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4088 } 4089 } 4090 break; 4091 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4092 default: break; 4093 } 4094 break; 4095 default: break; 4096 } 4097 } else if (pheight > 0) { 4098 switch (coneSize) { 4099 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4100 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4101 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4102 default: break; 4103 } 4104 } 4105 } 4106 *pt = ct; 4107 PetscFunctionReturn(0); 4108 } 4109 4110 /*@ 4111 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4112 4113 Collective on dm 4114 4115 Input Parameter: 4116 . mesh - The DMPlex 4117 4118 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4119 4120 Level: developer 4121 4122 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4123 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4124 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4125 4126 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4127 @*/ 4128 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4129 { 4130 DM_Plex *mesh; 4131 DMLabel ctLabel; 4132 PetscInt pStart, pEnd, p; 4133 4134 PetscFunctionBegin; 4135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4136 mesh = (DM_Plex *) dm->data; 4137 PetscCall(DMCreateLabel(dm, "celltype")); 4138 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4139 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4140 for (p = pStart; p < pEnd; ++p) { 4141 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4142 PetscInt pdepth; 4143 4144 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4145 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4146 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4147 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4148 } 4149 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4150 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4151 PetscFunctionReturn(0); 4152 } 4153 4154 /*@C 4155 DMPlexGetJoin - Get an array for the join of the set of points 4156 4157 Not Collective 4158 4159 Input Parameters: 4160 + dm - The DMPlex object 4161 . numPoints - The number of input points for the join 4162 - points - The input points 4163 4164 Output Parameters: 4165 + numCoveredPoints - The number of points in the join 4166 - coveredPoints - The points in the join 4167 4168 Level: intermediate 4169 4170 Note: Currently, this is restricted to a single level join 4171 4172 Fortran Notes: 4173 Since it returns an array, this routine is only available in Fortran 90, and you must 4174 include petsc.h90 in your code. 4175 4176 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4177 4178 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4179 @*/ 4180 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4181 { 4182 DM_Plex *mesh = (DM_Plex*) dm->data; 4183 PetscInt *join[2]; 4184 PetscInt joinSize, i = 0; 4185 PetscInt dof, off, p, c, m; 4186 PetscInt maxSupportSize; 4187 4188 PetscFunctionBegin; 4189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4190 PetscValidIntPointer(points, 3); 4191 PetscValidIntPointer(numCoveredPoints, 4); 4192 PetscValidPointer(coveredPoints, 5); 4193 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4194 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4195 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4196 /* Copy in support of first point */ 4197 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4198 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4199 for (joinSize = 0; joinSize < dof; ++joinSize) { 4200 join[i][joinSize] = mesh->supports[off+joinSize]; 4201 } 4202 /* Check each successive support */ 4203 for (p = 1; p < numPoints; ++p) { 4204 PetscInt newJoinSize = 0; 4205 4206 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4207 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4208 for (c = 0; c < dof; ++c) { 4209 const PetscInt point = mesh->supports[off+c]; 4210 4211 for (m = 0; m < joinSize; ++m) { 4212 if (point == join[i][m]) { 4213 join[1-i][newJoinSize++] = point; 4214 break; 4215 } 4216 } 4217 } 4218 joinSize = newJoinSize; 4219 i = 1-i; 4220 } 4221 *numCoveredPoints = joinSize; 4222 *coveredPoints = join[i]; 4223 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4224 PetscFunctionReturn(0); 4225 } 4226 4227 /*@C 4228 DMPlexRestoreJoin - Restore an array for the join of the set of points 4229 4230 Not Collective 4231 4232 Input Parameters: 4233 + dm - The DMPlex object 4234 . numPoints - The number of input points for the join 4235 - points - The input points 4236 4237 Output Parameters: 4238 + numCoveredPoints - The number of points in the join 4239 - coveredPoints - The points in the join 4240 4241 Fortran Notes: 4242 Since it returns an array, this routine is only available in Fortran 90, and you must 4243 include petsc.h90 in your code. 4244 4245 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4246 4247 Level: intermediate 4248 4249 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4250 @*/ 4251 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4252 { 4253 PetscFunctionBegin; 4254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4255 if (points) PetscValidIntPointer(points,3); 4256 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4257 PetscValidPointer(coveredPoints, 5); 4258 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4259 if (numCoveredPoints) *numCoveredPoints = 0; 4260 PetscFunctionReturn(0); 4261 } 4262 4263 /*@C 4264 DMPlexGetFullJoin - Get an array for the join of the set of points 4265 4266 Not Collective 4267 4268 Input Parameters: 4269 + dm - The DMPlex object 4270 . numPoints - The number of input points for the join 4271 - points - The input points 4272 4273 Output Parameters: 4274 + numCoveredPoints - The number of points in the join 4275 - coveredPoints - The points in the join 4276 4277 Fortran Notes: 4278 Since it returns an array, this routine is only available in Fortran 90, and you must 4279 include petsc.h90 in your code. 4280 4281 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4282 4283 Level: intermediate 4284 4285 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4286 @*/ 4287 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4288 { 4289 PetscInt *offsets, **closures; 4290 PetscInt *join[2]; 4291 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4292 PetscInt p, d, c, m, ms; 4293 4294 PetscFunctionBegin; 4295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4296 PetscValidIntPointer(points, 3); 4297 PetscValidIntPointer(numCoveredPoints, 4); 4298 PetscValidPointer(coveredPoints, 5); 4299 4300 PetscCall(DMPlexGetDepth(dm, &depth)); 4301 PetscCall(PetscCalloc1(numPoints, &closures)); 4302 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4303 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4304 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4305 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4306 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4307 4308 for (p = 0; p < numPoints; ++p) { 4309 PetscInt closureSize; 4310 4311 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4312 4313 offsets[p*(depth+2)+0] = 0; 4314 for (d = 0; d < depth+1; ++d) { 4315 PetscInt pStart, pEnd, i; 4316 4317 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4318 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4319 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4320 offsets[p*(depth+2)+d+1] = i; 4321 break; 4322 } 4323 } 4324 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4325 } 4326 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); 4327 } 4328 for (d = 0; d < depth+1; ++d) { 4329 PetscInt dof; 4330 4331 /* Copy in support of first point */ 4332 dof = offsets[d+1] - offsets[d]; 4333 for (joinSize = 0; joinSize < dof; ++joinSize) { 4334 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4335 } 4336 /* Check each successive cone */ 4337 for (p = 1; p < numPoints && joinSize; ++p) { 4338 PetscInt newJoinSize = 0; 4339 4340 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4341 for (c = 0; c < dof; ++c) { 4342 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4343 4344 for (m = 0; m < joinSize; ++m) { 4345 if (point == join[i][m]) { 4346 join[1-i][newJoinSize++] = point; 4347 break; 4348 } 4349 } 4350 } 4351 joinSize = newJoinSize; 4352 i = 1-i; 4353 } 4354 if (joinSize) break; 4355 } 4356 *numCoveredPoints = joinSize; 4357 *coveredPoints = join[i]; 4358 for (p = 0; p < numPoints; ++p) { 4359 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4360 } 4361 PetscCall(PetscFree(closures)); 4362 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4363 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4364 PetscFunctionReturn(0); 4365 } 4366 4367 /*@C 4368 DMPlexGetMeet - Get an array for the meet of the set of points 4369 4370 Not Collective 4371 4372 Input Parameters: 4373 + dm - The DMPlex object 4374 . numPoints - The number of input points for the meet 4375 - points - The input points 4376 4377 Output Parameters: 4378 + numCoveredPoints - The number of points in the meet 4379 - coveredPoints - The points in the meet 4380 4381 Level: intermediate 4382 4383 Note: Currently, this is restricted to a single level meet 4384 4385 Fortran Notes: 4386 Since it returns an array, this routine is only available in Fortran 90, and you must 4387 include petsc.h90 in your code. 4388 4389 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4390 4391 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4392 @*/ 4393 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4394 { 4395 DM_Plex *mesh = (DM_Plex*) dm->data; 4396 PetscInt *meet[2]; 4397 PetscInt meetSize, i = 0; 4398 PetscInt dof, off, p, c, m; 4399 PetscInt maxConeSize; 4400 4401 PetscFunctionBegin; 4402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4403 PetscValidIntPointer(points, 3); 4404 PetscValidIntPointer(numCoveringPoints, 4); 4405 PetscValidPointer(coveringPoints, 5); 4406 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4407 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4408 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4409 /* Copy in cone of first point */ 4410 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4411 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4412 for (meetSize = 0; meetSize < dof; ++meetSize) { 4413 meet[i][meetSize] = mesh->cones[off+meetSize]; 4414 } 4415 /* Check each successive cone */ 4416 for (p = 1; p < numPoints; ++p) { 4417 PetscInt newMeetSize = 0; 4418 4419 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4420 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4421 for (c = 0; c < dof; ++c) { 4422 const PetscInt point = mesh->cones[off+c]; 4423 4424 for (m = 0; m < meetSize; ++m) { 4425 if (point == meet[i][m]) { 4426 meet[1-i][newMeetSize++] = point; 4427 break; 4428 } 4429 } 4430 } 4431 meetSize = newMeetSize; 4432 i = 1-i; 4433 } 4434 *numCoveringPoints = meetSize; 4435 *coveringPoints = meet[i]; 4436 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4437 PetscFunctionReturn(0); 4438 } 4439 4440 /*@C 4441 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4442 4443 Not Collective 4444 4445 Input Parameters: 4446 + dm - The DMPlex object 4447 . numPoints - The number of input points for the meet 4448 - points - The input points 4449 4450 Output Parameters: 4451 + numCoveredPoints - The number of points in the meet 4452 - coveredPoints - The points in the meet 4453 4454 Level: intermediate 4455 4456 Fortran Notes: 4457 Since it returns an array, this routine is only available in Fortran 90, and you must 4458 include petsc.h90 in your code. 4459 4460 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4461 4462 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4463 @*/ 4464 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4465 { 4466 PetscFunctionBegin; 4467 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4468 if (points) PetscValidIntPointer(points,3); 4469 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4470 PetscValidPointer(coveredPoints,5); 4471 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4472 if (numCoveredPoints) *numCoveredPoints = 0; 4473 PetscFunctionReturn(0); 4474 } 4475 4476 /*@C 4477 DMPlexGetFullMeet - Get an array for the meet of the set of points 4478 4479 Not Collective 4480 4481 Input Parameters: 4482 + dm - The DMPlex object 4483 . numPoints - The number of input points for the meet 4484 - points - The input points 4485 4486 Output Parameters: 4487 + numCoveredPoints - The number of points in the meet 4488 - coveredPoints - The points in the meet 4489 4490 Level: intermediate 4491 4492 Fortran Notes: 4493 Since it returns an array, this routine is only available in Fortran 90, and you must 4494 include petsc.h90 in your code. 4495 4496 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4497 4498 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4499 @*/ 4500 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4501 { 4502 PetscInt *offsets, **closures; 4503 PetscInt *meet[2]; 4504 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4505 PetscInt p, h, c, m, mc; 4506 4507 PetscFunctionBegin; 4508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4509 PetscValidIntPointer(points, 3); 4510 PetscValidIntPointer(numCoveredPoints, 4); 4511 PetscValidPointer(coveredPoints, 5); 4512 4513 PetscCall(DMPlexGetDepth(dm, &height)); 4514 PetscCall(PetscMalloc1(numPoints, &closures)); 4515 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4516 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4517 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4518 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4519 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4520 4521 for (p = 0; p < numPoints; ++p) { 4522 PetscInt closureSize; 4523 4524 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4525 4526 offsets[p*(height+2)+0] = 0; 4527 for (h = 0; h < height+1; ++h) { 4528 PetscInt pStart, pEnd, i; 4529 4530 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4531 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4532 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4533 offsets[p*(height+2)+h+1] = i; 4534 break; 4535 } 4536 } 4537 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4538 } 4539 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); 4540 } 4541 for (h = 0; h < height+1; ++h) { 4542 PetscInt dof; 4543 4544 /* Copy in cone of first point */ 4545 dof = offsets[h+1] - offsets[h]; 4546 for (meetSize = 0; meetSize < dof; ++meetSize) { 4547 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4548 } 4549 /* Check each successive cone */ 4550 for (p = 1; p < numPoints && meetSize; ++p) { 4551 PetscInt newMeetSize = 0; 4552 4553 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4554 for (c = 0; c < dof; ++c) { 4555 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4556 4557 for (m = 0; m < meetSize; ++m) { 4558 if (point == meet[i][m]) { 4559 meet[1-i][newMeetSize++] = point; 4560 break; 4561 } 4562 } 4563 } 4564 meetSize = newMeetSize; 4565 i = 1-i; 4566 } 4567 if (meetSize) break; 4568 } 4569 *numCoveredPoints = meetSize; 4570 *coveredPoints = meet[i]; 4571 for (p = 0; p < numPoints; ++p) { 4572 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4573 } 4574 PetscCall(PetscFree(closures)); 4575 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4576 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4577 PetscFunctionReturn(0); 4578 } 4579 4580 /*@C 4581 DMPlexEqual - Determine if two DMs have the same topology 4582 4583 Not Collective 4584 4585 Input Parameters: 4586 + dmA - A DMPlex object 4587 - dmB - A DMPlex object 4588 4589 Output Parameters: 4590 . equal - PETSC_TRUE if the topologies are identical 4591 4592 Level: intermediate 4593 4594 Notes: 4595 We are not solving graph isomorphism, so we do not permutation. 4596 4597 .seealso: `DMPlexGetCone()` 4598 @*/ 4599 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4600 { 4601 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4602 4603 PetscFunctionBegin; 4604 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4605 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4606 PetscValidBoolPointer(equal, 3); 4607 4608 *equal = PETSC_FALSE; 4609 PetscCall(DMPlexGetDepth(dmA, &depth)); 4610 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4611 if (depth != depthB) PetscFunctionReturn(0); 4612 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4613 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4614 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4615 for (p = pStart; p < pEnd; ++p) { 4616 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4617 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4618 4619 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4620 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4621 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4622 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4623 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4624 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4625 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4626 for (c = 0; c < coneSize; ++c) { 4627 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4628 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4629 } 4630 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4631 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4632 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4633 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4634 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4635 for (s = 0; s < supportSize; ++s) { 4636 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4637 } 4638 } 4639 *equal = PETSC_TRUE; 4640 PetscFunctionReturn(0); 4641 } 4642 4643 /*@C 4644 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4645 4646 Not Collective 4647 4648 Input Parameters: 4649 + dm - The DMPlex 4650 . cellDim - The cell dimension 4651 - numCorners - The number of vertices on a cell 4652 4653 Output Parameters: 4654 . numFaceVertices - The number of vertices on a face 4655 4656 Level: developer 4657 4658 Notes: 4659 Of course this can only work for a restricted set of symmetric shapes 4660 4661 .seealso: `DMPlexGetCone()` 4662 @*/ 4663 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4664 { 4665 MPI_Comm comm; 4666 4667 PetscFunctionBegin; 4668 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4669 PetscValidIntPointer(numFaceVertices,4); 4670 switch (cellDim) { 4671 case 0: 4672 *numFaceVertices = 0; 4673 break; 4674 case 1: 4675 *numFaceVertices = 1; 4676 break; 4677 case 2: 4678 switch (numCorners) { 4679 case 3: /* triangle */ 4680 *numFaceVertices = 2; /* Edge has 2 vertices */ 4681 break; 4682 case 4: /* quadrilateral */ 4683 *numFaceVertices = 2; /* Edge has 2 vertices */ 4684 break; 4685 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4686 *numFaceVertices = 3; /* Edge has 3 vertices */ 4687 break; 4688 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4689 *numFaceVertices = 3; /* Edge has 3 vertices */ 4690 break; 4691 default: 4692 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4693 } 4694 break; 4695 case 3: 4696 switch (numCorners) { 4697 case 4: /* tetradehdron */ 4698 *numFaceVertices = 3; /* Face has 3 vertices */ 4699 break; 4700 case 6: /* tet cohesive cells */ 4701 *numFaceVertices = 4; /* Face has 4 vertices */ 4702 break; 4703 case 8: /* hexahedron */ 4704 *numFaceVertices = 4; /* Face has 4 vertices */ 4705 break; 4706 case 9: /* tet cohesive Lagrange cells */ 4707 *numFaceVertices = 6; /* Face has 6 vertices */ 4708 break; 4709 case 10: /* quadratic tetrahedron */ 4710 *numFaceVertices = 6; /* Face has 6 vertices */ 4711 break; 4712 case 12: /* hex cohesive Lagrange cells */ 4713 *numFaceVertices = 6; /* Face has 6 vertices */ 4714 break; 4715 case 18: /* quadratic tet cohesive Lagrange cells */ 4716 *numFaceVertices = 6; /* Face has 6 vertices */ 4717 break; 4718 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4719 *numFaceVertices = 9; /* Face has 9 vertices */ 4720 break; 4721 default: 4722 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4723 } 4724 break; 4725 default: 4726 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4727 } 4728 PetscFunctionReturn(0); 4729 } 4730 4731 /*@ 4732 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4733 4734 Not Collective 4735 4736 Input Parameter: 4737 . dm - The DMPlex object 4738 4739 Output Parameter: 4740 . depthLabel - The DMLabel recording point depth 4741 4742 Level: developer 4743 4744 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4745 @*/ 4746 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4747 { 4748 PetscFunctionBegin; 4749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4750 PetscValidPointer(depthLabel, 2); 4751 *depthLabel = dm->depthLabel; 4752 PetscFunctionReturn(0); 4753 } 4754 4755 /*@ 4756 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4757 4758 Not Collective 4759 4760 Input Parameter: 4761 . dm - The DMPlex object 4762 4763 Output Parameter: 4764 . depth - The number of strata (breadth first levels) in the DAG 4765 4766 Level: developer 4767 4768 Notes: 4769 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4770 The point depth is described more in detail in DMPlexGetDepthStratum(). 4771 An empty mesh gives -1. 4772 4773 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4774 @*/ 4775 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4776 { 4777 DMLabel label; 4778 PetscInt d = 0; 4779 4780 PetscFunctionBegin; 4781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4782 PetscValidIntPointer(depth, 2); 4783 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4784 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4785 *depth = d-1; 4786 PetscFunctionReturn(0); 4787 } 4788 4789 /*@ 4790 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4791 4792 Not Collective 4793 4794 Input Parameters: 4795 + dm - The DMPlex object 4796 - depth - The requested depth 4797 4798 Output Parameters: 4799 + start - The first point at this depth 4800 - end - One beyond the last point at this depth 4801 4802 Notes: 4803 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4804 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4805 higher dimension, e.g., "edges". 4806 4807 Level: developer 4808 4809 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4810 @*/ 4811 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4812 { 4813 DMLabel label; 4814 PetscInt pStart, pEnd; 4815 4816 PetscFunctionBegin; 4817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4818 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4819 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4820 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4821 if (pStart == pEnd) PetscFunctionReturn(0); 4822 if (depth < 0) { 4823 if (start) *start = pStart; 4824 if (end) *end = pEnd; 4825 PetscFunctionReturn(0); 4826 } 4827 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4828 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4829 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4830 PetscFunctionReturn(0); 4831 } 4832 4833 /*@ 4834 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4835 4836 Not Collective 4837 4838 Input Parameters: 4839 + dm - The DMPlex object 4840 - height - The requested height 4841 4842 Output Parameters: 4843 + start - The first point at this height 4844 - end - One beyond the last point at this height 4845 4846 Notes: 4847 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4848 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4849 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4850 4851 Level: developer 4852 4853 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4854 @*/ 4855 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4856 { 4857 DMLabel label; 4858 PetscInt depth, pStart, pEnd; 4859 4860 PetscFunctionBegin; 4861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4862 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4863 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4864 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4865 if (pStart == pEnd) PetscFunctionReturn(0); 4866 if (height < 0) { 4867 if (start) *start = pStart; 4868 if (end) *end = pEnd; 4869 PetscFunctionReturn(0); 4870 } 4871 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4872 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4873 PetscCall(DMLabelGetNumValues(label, &depth)); 4874 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4875 PetscFunctionReturn(0); 4876 } 4877 4878 /*@ 4879 DMPlexGetPointDepth - Get the depth of a given point 4880 4881 Not Collective 4882 4883 Input Parameters: 4884 + dm - The DMPlex object 4885 - point - The point 4886 4887 Output Parameter: 4888 . depth - The depth of the point 4889 4890 Level: intermediate 4891 4892 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4893 @*/ 4894 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4895 { 4896 PetscFunctionBegin; 4897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4898 PetscValidIntPointer(depth, 3); 4899 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4900 PetscFunctionReturn(0); 4901 } 4902 4903 /*@ 4904 DMPlexGetPointHeight - Get the height of a given point 4905 4906 Not Collective 4907 4908 Input Parameters: 4909 + dm - The DMPlex object 4910 - point - The point 4911 4912 Output Parameter: 4913 . height - The height of the point 4914 4915 Level: intermediate 4916 4917 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4918 @*/ 4919 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4920 { 4921 PetscInt n, pDepth; 4922 4923 PetscFunctionBegin; 4924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4925 PetscValidIntPointer(height, 3); 4926 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4927 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4928 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4929 PetscFunctionReturn(0); 4930 } 4931 4932 /*@ 4933 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4934 4935 Not Collective 4936 4937 Input Parameter: 4938 . dm - The DMPlex object 4939 4940 Output Parameter: 4941 . celltypeLabel - The DMLabel recording cell polytope type 4942 4943 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4944 DMCreateLabel(dm, "celltype") beforehand. 4945 4946 Level: developer 4947 4948 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4949 @*/ 4950 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4951 { 4952 PetscFunctionBegin; 4953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4954 PetscValidPointer(celltypeLabel, 2); 4955 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4956 *celltypeLabel = dm->celltypeLabel; 4957 PetscFunctionReturn(0); 4958 } 4959 4960 /*@ 4961 DMPlexGetCellType - Get the polytope type of a given cell 4962 4963 Not Collective 4964 4965 Input Parameters: 4966 + dm - The DMPlex object 4967 - cell - The cell 4968 4969 Output Parameter: 4970 . celltype - The polytope type of the cell 4971 4972 Level: intermediate 4973 4974 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4975 @*/ 4976 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4977 { 4978 DMLabel label; 4979 PetscInt ct; 4980 4981 PetscFunctionBegin; 4982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4983 PetscValidPointer(celltype, 3); 4984 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4985 PetscCall(DMLabelGetValue(label, cell, &ct)); 4986 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4987 *celltype = (DMPolytopeType) ct; 4988 PetscFunctionReturn(0); 4989 } 4990 4991 /*@ 4992 DMPlexSetCellType - Set the polytope type of a given cell 4993 4994 Not Collective 4995 4996 Input Parameters: 4997 + dm - The DMPlex object 4998 . cell - The cell 4999 - celltype - The polytope type of the cell 5000 5001 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5002 is executed. This function will override the computed type. However, if automatic classification will not succeed 5003 and a user wants to manually specify all types, the classification must be disabled by calling 5004 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5005 5006 Level: advanced 5007 5008 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5009 @*/ 5010 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5011 { 5012 DMLabel label; 5013 5014 PetscFunctionBegin; 5015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5016 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5017 PetscCall(DMLabelSetValue(label, cell, celltype)); 5018 PetscFunctionReturn(0); 5019 } 5020 5021 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5022 { 5023 PetscSection section, s; 5024 Mat m; 5025 PetscInt maxHeight; 5026 5027 PetscFunctionBegin; 5028 PetscCall(DMClone(dm, cdm)); 5029 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5030 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5031 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5032 PetscCall(DMSetLocalSection(*cdm, section)); 5033 PetscCall(PetscSectionDestroy(§ion)); 5034 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5035 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5036 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5037 PetscCall(PetscSectionDestroy(&s)); 5038 PetscCall(MatDestroy(&m)); 5039 5040 PetscCall(DMSetNumFields(*cdm, 1)); 5041 PetscCall(DMCreateDS(*cdm)); 5042 PetscFunctionReturn(0); 5043 } 5044 5045 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5046 { 5047 Vec coordsLocal; 5048 DM coordsDM; 5049 5050 PetscFunctionBegin; 5051 *field = NULL; 5052 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5053 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5054 if (coordsLocal && coordsDM) { 5055 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5056 } 5057 PetscFunctionReturn(0); 5058 } 5059 5060 /*@C 5061 DMPlexGetConeSection - Return a section which describes the layout of cone data 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 . dm - The DMPlex object 5067 5068 Output Parameter: 5069 . section - The PetscSection object 5070 5071 Level: developer 5072 5073 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5074 @*/ 5075 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5076 { 5077 DM_Plex *mesh = (DM_Plex*) dm->data; 5078 5079 PetscFunctionBegin; 5080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5081 if (section) *section = mesh->coneSection; 5082 PetscFunctionReturn(0); 5083 } 5084 5085 /*@C 5086 DMPlexGetSupportSection - Return a section which describes the layout of support data 5087 5088 Not Collective 5089 5090 Input Parameters: 5091 . dm - The DMPlex object 5092 5093 Output Parameter: 5094 . section - The PetscSection object 5095 5096 Level: developer 5097 5098 .seealso: `DMPlexGetConeSection()` 5099 @*/ 5100 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5101 { 5102 DM_Plex *mesh = (DM_Plex*) dm->data; 5103 5104 PetscFunctionBegin; 5105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5106 if (section) *section = mesh->supportSection; 5107 PetscFunctionReturn(0); 5108 } 5109 5110 /*@C 5111 DMPlexGetCones - Return cone data 5112 5113 Not Collective 5114 5115 Input Parameters: 5116 . dm - The DMPlex object 5117 5118 Output Parameter: 5119 . cones - The cone for each point 5120 5121 Level: developer 5122 5123 .seealso: `DMPlexGetConeSection()` 5124 @*/ 5125 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5126 { 5127 DM_Plex *mesh = (DM_Plex*) dm->data; 5128 5129 PetscFunctionBegin; 5130 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5131 if (cones) *cones = mesh->cones; 5132 PetscFunctionReturn(0); 5133 } 5134 5135 /*@C 5136 DMPlexGetConeOrientations - Return cone orientation data 5137 5138 Not Collective 5139 5140 Input Parameters: 5141 . dm - The DMPlex object 5142 5143 Output Parameter: 5144 . coneOrientations - The array of cone orientations for all points 5145 5146 Level: developer 5147 5148 Notes: 5149 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5150 5151 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5152 5153 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5154 @*/ 5155 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5156 { 5157 DM_Plex *mesh = (DM_Plex*) dm->data; 5158 5159 PetscFunctionBegin; 5160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5161 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5162 PetscFunctionReturn(0); 5163 } 5164 5165 /******************************** FEM Support **********************************/ 5166 5167 /* 5168 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5169 representing a line in the section. 5170 */ 5171 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5172 { 5173 PetscFunctionBeginHot; 5174 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5175 if (line < 0) { 5176 *k = 0; 5177 *Nc = 0; 5178 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5179 *k = 1; 5180 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5181 /* An order k SEM disc has k-1 dofs on an edge */ 5182 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5183 *k = *k / *Nc + 1; 5184 } 5185 PetscFunctionReturn(0); 5186 } 5187 5188 /*@ 5189 5190 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5191 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5192 section provided (or the section of the DM). 5193 5194 Input Parameters: 5195 + dm - The DM 5196 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5197 - section - The PetscSection to reorder, or NULL for the default section 5198 5199 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5200 degree of the basis. 5201 5202 Example: 5203 A typical interpolated single-quad mesh might order points as 5204 .vb 5205 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5206 5207 v4 -- e6 -- v3 5208 | | 5209 e7 c0 e8 5210 | | 5211 v1 -- e5 -- v2 5212 .ve 5213 5214 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5215 dofs in the order of points, e.g., 5216 .vb 5217 c0 -> [0,1,2,3] 5218 v1 -> [4] 5219 ... 5220 e5 -> [8, 9] 5221 .ve 5222 5223 which corresponds to the dofs 5224 .vb 5225 6 10 11 7 5226 13 2 3 15 5227 12 0 1 14 5228 4 8 9 5 5229 .ve 5230 5231 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5232 .vb 5233 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5234 .ve 5235 5236 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5237 .vb 5238 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5239 .ve 5240 5241 Level: developer 5242 5243 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5244 @*/ 5245 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5246 { 5247 DMLabel label; 5248 PetscInt dim, depth = -1, eStart = -1, Nf; 5249 PetscBool vertexchart; 5250 5251 PetscFunctionBegin; 5252 PetscCall(DMGetDimension(dm, &dim)); 5253 if (dim < 1) PetscFunctionReturn(0); 5254 if (point < 0) { 5255 PetscInt sStart,sEnd; 5256 5257 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5258 point = sEnd-sStart ? sStart : point; 5259 } 5260 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5261 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5262 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5263 if (depth == 1) {eStart = point;} 5264 else if (depth == dim) { 5265 const PetscInt *cone; 5266 5267 PetscCall(DMPlexGetCone(dm, point, &cone)); 5268 if (dim == 2) eStart = cone[0]; 5269 else if (dim == 3) { 5270 const PetscInt *cone2; 5271 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5272 eStart = cone2[0]; 5273 } 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); 5274 } 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); 5275 { /* Determine whether the chart covers all points or just vertices. */ 5276 PetscInt pStart,pEnd,cStart,cEnd; 5277 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5278 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5279 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5280 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5281 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5282 } 5283 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5284 for (PetscInt d=1; d<=dim; d++) { 5285 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5286 PetscInt *perm; 5287 5288 for (f = 0; f < Nf; ++f) { 5289 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5290 size += PetscPowInt(k+1, d)*Nc; 5291 } 5292 PetscCall(PetscMalloc1(size, &perm)); 5293 for (f = 0; f < Nf; ++f) { 5294 switch (d) { 5295 case 1: 5296 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5297 /* 5298 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5299 We want [ vtx0; edge of length k-1; vtx1 ] 5300 */ 5301 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5302 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5303 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5304 foffset = offset; 5305 break; 5306 case 2: 5307 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5308 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5309 /* The SEM order is 5310 5311 v_lb, {e_b}, v_rb, 5312 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5313 v_lt, reverse {e_t}, v_rt 5314 */ 5315 { 5316 const PetscInt of = 0; 5317 const PetscInt oeb = of + PetscSqr(k-1); 5318 const PetscInt oer = oeb + (k-1); 5319 const PetscInt oet = oer + (k-1); 5320 const PetscInt oel = oet + (k-1); 5321 const PetscInt ovlb = oel + (k-1); 5322 const PetscInt ovrb = ovlb + 1; 5323 const PetscInt ovrt = ovrb + 1; 5324 const PetscInt ovlt = ovrt + 1; 5325 PetscInt o; 5326 5327 /* bottom */ 5328 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5329 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5330 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5331 /* middle */ 5332 for (i = 0; i < k-1; ++i) { 5333 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5334 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; 5335 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5336 } 5337 /* top */ 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5339 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5341 foffset = offset; 5342 } 5343 break; 5344 case 3: 5345 /* The original hex closure is 5346 5347 {c, 5348 f_b, f_t, f_f, f_b, f_r, f_l, 5349 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5350 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5351 */ 5352 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5353 /* The SEM order is 5354 Bottom Slice 5355 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5356 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5357 v_blb, {e_bb}, v_brb, 5358 5359 Middle Slice (j) 5360 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5361 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5362 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5363 5364 Top Slice 5365 v_tlf, {e_tf}, v_trf, 5366 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5367 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5368 */ 5369 { 5370 const PetscInt oc = 0; 5371 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5372 const PetscInt oft = ofb + PetscSqr(k-1); 5373 const PetscInt off = oft + PetscSqr(k-1); 5374 const PetscInt ofk = off + PetscSqr(k-1); 5375 const PetscInt ofr = ofk + PetscSqr(k-1); 5376 const PetscInt ofl = ofr + PetscSqr(k-1); 5377 const PetscInt oebl = ofl + PetscSqr(k-1); 5378 const PetscInt oebb = oebl + (k-1); 5379 const PetscInt oebr = oebb + (k-1); 5380 const PetscInt oebf = oebr + (k-1); 5381 const PetscInt oetf = oebf + (k-1); 5382 const PetscInt oetr = oetf + (k-1); 5383 const PetscInt oetb = oetr + (k-1); 5384 const PetscInt oetl = oetb + (k-1); 5385 const PetscInt oerf = oetl + (k-1); 5386 const PetscInt oelf = oerf + (k-1); 5387 const PetscInt oelb = oelf + (k-1); 5388 const PetscInt oerb = oelb + (k-1); 5389 const PetscInt ovblf = oerb + (k-1); 5390 const PetscInt ovblb = ovblf + 1; 5391 const PetscInt ovbrb = ovblb + 1; 5392 const PetscInt ovbrf = ovbrb + 1; 5393 const PetscInt ovtlf = ovbrf + 1; 5394 const PetscInt ovtrf = ovtlf + 1; 5395 const PetscInt ovtrb = ovtrf + 1; 5396 const PetscInt ovtlb = ovtrb + 1; 5397 PetscInt o, n; 5398 5399 /* Bottom Slice */ 5400 /* bottom */ 5401 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5402 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5403 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5404 /* middle */ 5405 for (i = 0; i < k-1; ++i) { 5406 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5407 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;} 5408 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5409 } 5410 /* top */ 5411 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5412 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5414 5415 /* Middle Slice */ 5416 for (j = 0; j < k-1; ++j) { 5417 /* bottom */ 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5419 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; 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5421 /* middle */ 5422 for (i = 0; i < k-1; ++i) { 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5424 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; 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5426 } 5427 /* top */ 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5429 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; 5430 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5431 } 5432 5433 /* Top Slice */ 5434 /* bottom */ 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5436 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5437 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5438 /* middle */ 5439 for (i = 0; i < k-1; ++i) { 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5441 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5442 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5443 } 5444 /* top */ 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5446 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5447 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5448 5449 foffset = offset; 5450 } 5451 break; 5452 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5453 } 5454 } 5455 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5456 /* Check permutation */ 5457 { 5458 PetscInt *check; 5459 5460 PetscCall(PetscMalloc1(size, &check)); 5461 for (i = 0; i < size; ++i) { 5462 check[i] = -1; 5463 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5464 } 5465 for (i = 0; i < size; ++i) check[perm[i]] = i; 5466 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5467 PetscCall(PetscFree(check)); 5468 } 5469 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5470 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5471 PetscInt *loc_perm; 5472 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5473 for (PetscInt i=0; i<size; i++) { 5474 loc_perm[i] = perm[i]; 5475 loc_perm[size+i] = size + perm[i]; 5476 } 5477 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5478 } 5479 } 5480 PetscFunctionReturn(0); 5481 } 5482 5483 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5484 { 5485 PetscDS prob; 5486 PetscInt depth, Nf, h; 5487 DMLabel label; 5488 5489 PetscFunctionBeginHot; 5490 PetscCall(DMGetDS(dm, &prob)); 5491 Nf = prob->Nf; 5492 label = dm->depthLabel; 5493 *dspace = NULL; 5494 if (field < Nf) { 5495 PetscObject disc = prob->disc[field]; 5496 5497 if (disc->classid == PETSCFE_CLASSID) { 5498 PetscDualSpace dsp; 5499 5500 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5501 PetscCall(DMLabelGetNumValues(label,&depth)); 5502 PetscCall(DMLabelGetValue(label,point,&h)); 5503 h = depth - 1 - h; 5504 if (h) { 5505 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5506 } else { 5507 *dspace = dsp; 5508 } 5509 } 5510 } 5511 PetscFunctionReturn(0); 5512 } 5513 5514 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5515 { 5516 PetscScalar *array, *vArray; 5517 const PetscInt *cone, *coneO; 5518 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5519 5520 PetscFunctionBeginHot; 5521 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5522 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5523 PetscCall(DMPlexGetCone(dm, point, &cone)); 5524 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5525 if (!values || !*values) { 5526 if ((point >= pStart) && (point < pEnd)) { 5527 PetscInt dof; 5528 5529 PetscCall(PetscSectionGetDof(section, point, &dof)); 5530 size += dof; 5531 } 5532 for (p = 0; p < numPoints; ++p) { 5533 const PetscInt cp = cone[p]; 5534 PetscInt dof; 5535 5536 if ((cp < pStart) || (cp >= pEnd)) continue; 5537 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5538 size += dof; 5539 } 5540 if (!values) { 5541 if (csize) *csize = size; 5542 PetscFunctionReturn(0); 5543 } 5544 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5545 } else { 5546 array = *values; 5547 } 5548 size = 0; 5549 PetscCall(VecGetArray(v, &vArray)); 5550 if ((point >= pStart) && (point < pEnd)) { 5551 PetscInt dof, off, d; 5552 PetscScalar *varr; 5553 5554 PetscCall(PetscSectionGetDof(section, point, &dof)); 5555 PetscCall(PetscSectionGetOffset(section, point, &off)); 5556 varr = &vArray[off]; 5557 for (d = 0; d < dof; ++d, ++offset) { 5558 array[offset] = varr[d]; 5559 } 5560 size += dof; 5561 } 5562 for (p = 0; p < numPoints; ++p) { 5563 const PetscInt cp = cone[p]; 5564 PetscInt o = coneO[p]; 5565 PetscInt dof, off, d; 5566 PetscScalar *varr; 5567 5568 if ((cp < pStart) || (cp >= pEnd)) continue; 5569 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5570 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5571 varr = &vArray[off]; 5572 if (o >= 0) { 5573 for (d = 0; d < dof; ++d, ++offset) { 5574 array[offset] = varr[d]; 5575 } 5576 } else { 5577 for (d = dof-1; d >= 0; --d, ++offset) { 5578 array[offset] = varr[d]; 5579 } 5580 } 5581 size += dof; 5582 } 5583 PetscCall(VecRestoreArray(v, &vArray)); 5584 if (!*values) { 5585 if (csize) *csize = size; 5586 *values = array; 5587 } else { 5588 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5589 *csize = size; 5590 } 5591 PetscFunctionReturn(0); 5592 } 5593 5594 /* Compress out points not in the section */ 5595 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5596 { 5597 const PetscInt np = *numPoints; 5598 PetscInt pStart, pEnd, p, q; 5599 5600 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5601 for (p = 0, q = 0; p < np; ++p) { 5602 const PetscInt r = points[p*2]; 5603 if ((r >= pStart) && (r < pEnd)) { 5604 points[q*2] = r; 5605 points[q*2+1] = points[p*2+1]; 5606 ++q; 5607 } 5608 } 5609 *numPoints = q; 5610 return 0; 5611 } 5612 5613 /* Compressed closure does not apply closure permutation */ 5614 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5615 { 5616 const PetscInt *cla = NULL; 5617 PetscInt np, *pts = NULL; 5618 5619 PetscFunctionBeginHot; 5620 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5621 if (*clPoints) { 5622 PetscInt dof, off; 5623 5624 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5625 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5626 PetscCall(ISGetIndices(*clPoints, &cla)); 5627 np = dof/2; 5628 pts = (PetscInt *) &cla[off]; 5629 } else { 5630 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5631 PetscCall(CompressPoints_Private(section, &np, pts)); 5632 } 5633 *numPoints = np; 5634 *points = pts; 5635 *clp = cla; 5636 PetscFunctionReturn(0); 5637 } 5638 5639 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5640 { 5641 PetscFunctionBeginHot; 5642 if (!*clPoints) { 5643 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5644 } else { 5645 PetscCall(ISRestoreIndices(*clPoints, clp)); 5646 } 5647 *numPoints = 0; 5648 *points = NULL; 5649 *clSec = NULL; 5650 *clPoints = NULL; 5651 *clp = NULL; 5652 PetscFunctionReturn(0); 5653 } 5654 5655 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5656 { 5657 PetscInt offset = 0, p; 5658 const PetscInt **perms = NULL; 5659 const PetscScalar **flips = NULL; 5660 5661 PetscFunctionBeginHot; 5662 *size = 0; 5663 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5664 for (p = 0; p < numPoints; p++) { 5665 const PetscInt point = points[2*p]; 5666 const PetscInt *perm = perms ? perms[p] : NULL; 5667 const PetscScalar *flip = flips ? flips[p] : NULL; 5668 PetscInt dof, off, d; 5669 const PetscScalar *varr; 5670 5671 PetscCall(PetscSectionGetDof(section, point, &dof)); 5672 PetscCall(PetscSectionGetOffset(section, point, &off)); 5673 varr = &vArray[off]; 5674 if (clperm) { 5675 if (perm) { 5676 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5677 } else { 5678 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5679 } 5680 if (flip) { 5681 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5682 } 5683 } else { 5684 if (perm) { 5685 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5686 } else { 5687 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5688 } 5689 if (flip) { 5690 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5691 } 5692 } 5693 offset += dof; 5694 } 5695 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5696 *size = offset; 5697 PetscFunctionReturn(0); 5698 } 5699 5700 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[]) 5701 { 5702 PetscInt offset = 0, f; 5703 5704 PetscFunctionBeginHot; 5705 *size = 0; 5706 for (f = 0; f < numFields; ++f) { 5707 PetscInt p; 5708 const PetscInt **perms = NULL; 5709 const PetscScalar **flips = NULL; 5710 5711 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5712 for (p = 0; p < numPoints; p++) { 5713 const PetscInt point = points[2*p]; 5714 PetscInt fdof, foff, b; 5715 const PetscScalar *varr; 5716 const PetscInt *perm = perms ? perms[p] : NULL; 5717 const PetscScalar *flip = flips ? flips[p] : NULL; 5718 5719 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5720 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5721 varr = &vArray[foff]; 5722 if (clperm) { 5723 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5724 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5725 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5726 } else { 5727 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5728 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5729 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5730 } 5731 offset += fdof; 5732 } 5733 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5734 } 5735 *size = offset; 5736 PetscFunctionReturn(0); 5737 } 5738 5739 /*@C 5740 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5741 5742 Not collective 5743 5744 Input Parameters: 5745 + dm - The DM 5746 . section - The section describing the layout in v, or NULL to use the default section 5747 . v - The local vector 5748 - point - The point in the DM 5749 5750 Input/Output Parameters: 5751 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5752 - values - An array to use for the values, or NULL to have it allocated automatically; 5753 if the user provided NULL, it is a borrowed array and should not be freed 5754 5755 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5756 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5757 $ assembly function, and a user may already have allocated storage for this operation. 5758 $ 5759 $ A typical use could be 5760 $ 5761 $ values = NULL; 5762 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5763 $ for (cl = 0; cl < clSize; ++cl) { 5764 $ <Compute on closure> 5765 $ } 5766 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5767 $ 5768 $ or 5769 $ 5770 $ PetscMalloc1(clMaxSize, &values); 5771 $ for (p = pStart; p < pEnd; ++p) { 5772 $ clSize = clMaxSize; 5773 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5774 $ for (cl = 0; cl < clSize; ++cl) { 5775 $ <Compute on closure> 5776 $ } 5777 $ } 5778 $ PetscFree(values); 5779 5780 Fortran Notes: 5781 Since it returns an array, this routine is only available in Fortran 90, and you must 5782 include petsc.h90 in your code. 5783 5784 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5785 5786 Level: intermediate 5787 5788 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5789 @*/ 5790 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5791 { 5792 PetscSection clSection; 5793 IS clPoints; 5794 PetscInt *points = NULL; 5795 const PetscInt *clp, *perm; 5796 PetscInt depth, numFields, numPoints, asize; 5797 5798 PetscFunctionBeginHot; 5799 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5800 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5801 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5802 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5803 PetscCall(DMPlexGetDepth(dm, &depth)); 5804 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5805 if (depth == 1 && numFields < 2) { 5806 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5807 PetscFunctionReturn(0); 5808 } 5809 /* Get points */ 5810 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5811 /* Get sizes */ 5812 asize = 0; 5813 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5814 PetscInt dof; 5815 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5816 asize += dof; 5817 } 5818 if (values) { 5819 const PetscScalar *vArray; 5820 PetscInt size; 5821 5822 if (*values) { 5823 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); 5824 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5825 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5826 PetscCall(VecGetArrayRead(v, &vArray)); 5827 /* Get values */ 5828 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5829 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5830 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5831 /* Cleanup array */ 5832 PetscCall(VecRestoreArrayRead(v, &vArray)); 5833 } 5834 if (csize) *csize = asize; 5835 /* Cleanup points */ 5836 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5837 PetscFunctionReturn(0); 5838 } 5839 5840 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5841 { 5842 DMLabel depthLabel; 5843 PetscSection clSection; 5844 IS clPoints; 5845 PetscScalar *array; 5846 const PetscScalar *vArray; 5847 PetscInt *points = NULL; 5848 const PetscInt *clp, *perm = NULL; 5849 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5850 5851 PetscFunctionBeginHot; 5852 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5853 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5854 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5855 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5856 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5857 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5858 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5859 if (mdepth == 1 && numFields < 2) { 5860 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5861 PetscFunctionReturn(0); 5862 } 5863 /* Get points */ 5864 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5865 for (clsize=0,p=0; p<Np; p++) { 5866 PetscInt dof; 5867 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5868 clsize += dof; 5869 } 5870 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5871 /* Filter points */ 5872 for (p = 0; p < numPoints*2; p += 2) { 5873 PetscInt dep; 5874 5875 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5876 if (dep != depth) continue; 5877 points[Np*2+0] = points[p]; 5878 points[Np*2+1] = points[p+1]; 5879 ++Np; 5880 } 5881 /* Get array */ 5882 if (!values || !*values) { 5883 PetscInt asize = 0, dof; 5884 5885 for (p = 0; p < Np*2; p += 2) { 5886 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5887 asize += dof; 5888 } 5889 if (!values) { 5890 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5891 if (csize) *csize = asize; 5892 PetscFunctionReturn(0); 5893 } 5894 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5895 } else { 5896 array = *values; 5897 } 5898 PetscCall(VecGetArrayRead(v, &vArray)); 5899 /* Get values */ 5900 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5901 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5902 /* Cleanup points */ 5903 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5904 /* Cleanup array */ 5905 PetscCall(VecRestoreArrayRead(v, &vArray)); 5906 if (!*values) { 5907 if (csize) *csize = size; 5908 *values = array; 5909 } else { 5910 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5911 *csize = size; 5912 } 5913 PetscFunctionReturn(0); 5914 } 5915 5916 /*@C 5917 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5918 5919 Not collective 5920 5921 Input Parameters: 5922 + dm - The DM 5923 . section - The section describing the layout in v, or NULL to use the default section 5924 . v - The local vector 5925 . point - The point in the DM 5926 . csize - The number of values in the closure, or NULL 5927 - values - The array of values, which is a borrowed array and should not be freed 5928 5929 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5930 5931 Fortran Notes: 5932 Since it returns an array, this routine is only available in Fortran 90, and you must 5933 include petsc.h90 in your code. 5934 5935 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5936 5937 Level: intermediate 5938 5939 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5940 @*/ 5941 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5942 { 5943 PetscInt size = 0; 5944 5945 PetscFunctionBegin; 5946 /* Should work without recalculating size */ 5947 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5948 *values = NULL; 5949 PetscFunctionReturn(0); 5950 } 5951 5952 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5953 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5954 5955 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[]) 5956 { 5957 PetscInt cdof; /* The number of constraints on this point */ 5958 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5959 PetscScalar *a; 5960 PetscInt off, cind = 0, k; 5961 5962 PetscFunctionBegin; 5963 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5964 PetscCall(PetscSectionGetOffset(section, point, &off)); 5965 a = &array[off]; 5966 if (!cdof || setBC) { 5967 if (clperm) { 5968 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5969 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5970 } else { 5971 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5972 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5973 } 5974 } else { 5975 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5976 if (clperm) { 5977 if (perm) {for (k = 0; k < dof; ++k) { 5978 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5979 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5980 } 5981 } else { 5982 for (k = 0; k < dof; ++k) { 5983 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5984 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5985 } 5986 } 5987 } else { 5988 if (perm) { 5989 for (k = 0; k < dof; ++k) { 5990 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5991 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5992 } 5993 } else { 5994 for (k = 0; k < dof; ++k) { 5995 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5996 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5997 } 5998 } 5999 } 6000 } 6001 PetscFunctionReturn(0); 6002 } 6003 6004 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[]) 6005 { 6006 PetscInt cdof; /* The number of constraints on this point */ 6007 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6008 PetscScalar *a; 6009 PetscInt off, cind = 0, k; 6010 6011 PetscFunctionBegin; 6012 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6013 PetscCall(PetscSectionGetOffset(section, point, &off)); 6014 a = &array[off]; 6015 if (cdof) { 6016 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6017 if (clperm) { 6018 if (perm) { 6019 for (k = 0; k < dof; ++k) { 6020 if ((cind < cdof) && (k == cdofs[cind])) { 6021 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6022 cind++; 6023 } 6024 } 6025 } else { 6026 for (k = 0; k < dof; ++k) { 6027 if ((cind < cdof) && (k == cdofs[cind])) { 6028 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6029 cind++; 6030 } 6031 } 6032 } 6033 } else { 6034 if (perm) { 6035 for (k = 0; k < dof; ++k) { 6036 if ((cind < cdof) && (k == cdofs[cind])) { 6037 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6038 cind++; 6039 } 6040 } 6041 } else { 6042 for (k = 0; k < dof; ++k) { 6043 if ((cind < cdof) && (k == cdofs[cind])) { 6044 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6045 cind++; 6046 } 6047 } 6048 } 6049 } 6050 } 6051 PetscFunctionReturn(0); 6052 } 6053 6054 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[]) 6055 { 6056 PetscScalar *a; 6057 PetscInt fdof, foff, fcdof, foffset = *offset; 6058 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6059 PetscInt cind = 0, b; 6060 6061 PetscFunctionBegin; 6062 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6063 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6064 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6065 a = &array[foff]; 6066 if (!fcdof || setBC) { 6067 if (clperm) { 6068 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6069 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6070 } else { 6071 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6072 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6073 } 6074 } else { 6075 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6076 if (clperm) { 6077 if (perm) { 6078 for (b = 0; b < fdof; b++) { 6079 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6080 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6081 } 6082 } else { 6083 for (b = 0; b < fdof; b++) { 6084 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6085 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6086 } 6087 } 6088 } else { 6089 if (perm) { 6090 for (b = 0; b < fdof; b++) { 6091 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6092 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6093 } 6094 } else { 6095 for (b = 0; b < fdof; b++) { 6096 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6097 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6098 } 6099 } 6100 } 6101 } 6102 *offset += fdof; 6103 PetscFunctionReturn(0); 6104 } 6105 6106 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[]) 6107 { 6108 PetscScalar *a; 6109 PetscInt fdof, foff, fcdof, foffset = *offset; 6110 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6111 PetscInt Nc, cind = 0, ncind = 0, b; 6112 PetscBool ncSet, fcSet; 6113 6114 PetscFunctionBegin; 6115 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6116 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6117 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6118 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6119 a = &array[foff]; 6120 if (fcdof) { 6121 /* We just override fcdof and fcdofs with Ncc and comps */ 6122 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6123 if (clperm) { 6124 if (perm) { 6125 if (comps) { 6126 for (b = 0; b < fdof; b++) { 6127 ncSet = fcSet = PETSC_FALSE; 6128 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6129 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6130 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6131 } 6132 } else { 6133 for (b = 0; b < fdof; b++) { 6134 if ((cind < fcdof) && (b == fcdofs[cind])) { 6135 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6136 ++cind; 6137 } 6138 } 6139 } 6140 } else { 6141 if (comps) { 6142 for (b = 0; b < fdof; b++) { 6143 ncSet = fcSet = PETSC_FALSE; 6144 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6145 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6146 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6147 } 6148 } else { 6149 for (b = 0; b < fdof; b++) { 6150 if ((cind < fcdof) && (b == fcdofs[cind])) { 6151 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6152 ++cind; 6153 } 6154 } 6155 } 6156 } 6157 } else { 6158 if (perm) { 6159 if (comps) { 6160 for (b = 0; b < fdof; b++) { 6161 ncSet = fcSet = PETSC_FALSE; 6162 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6163 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6164 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6165 } 6166 } else { 6167 for (b = 0; b < fdof; b++) { 6168 if ((cind < fcdof) && (b == fcdofs[cind])) { 6169 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6170 ++cind; 6171 } 6172 } 6173 } 6174 } else { 6175 if (comps) { 6176 for (b = 0; b < fdof; b++) { 6177 ncSet = fcSet = PETSC_FALSE; 6178 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6179 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6180 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6181 } 6182 } else { 6183 for (b = 0; b < fdof; b++) { 6184 if ((cind < fcdof) && (b == fcdofs[cind])) { 6185 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6186 ++cind; 6187 } 6188 } 6189 } 6190 } 6191 } 6192 } 6193 *offset += fdof; 6194 PetscFunctionReturn(0); 6195 } 6196 6197 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6198 { 6199 PetscScalar *array; 6200 const PetscInt *cone, *coneO; 6201 PetscInt pStart, pEnd, p, numPoints, off, dof; 6202 6203 PetscFunctionBeginHot; 6204 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6205 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6206 PetscCall(DMPlexGetCone(dm, point, &cone)); 6207 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6208 PetscCall(VecGetArray(v, &array)); 6209 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6210 const PetscInt cp = !p ? point : cone[p-1]; 6211 const PetscInt o = !p ? 0 : coneO[p-1]; 6212 6213 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6214 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6215 /* ADD_VALUES */ 6216 { 6217 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6218 PetscScalar *a; 6219 PetscInt cdof, coff, cind = 0, k; 6220 6221 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6222 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6223 a = &array[coff]; 6224 if (!cdof) { 6225 if (o >= 0) { 6226 for (k = 0; k < dof; ++k) { 6227 a[k] += values[off+k]; 6228 } 6229 } else { 6230 for (k = 0; k < dof; ++k) { 6231 a[k] += values[off+dof-k-1]; 6232 } 6233 } 6234 } else { 6235 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6236 if (o >= 0) { 6237 for (k = 0; k < dof; ++k) { 6238 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6239 a[k] += values[off+k]; 6240 } 6241 } else { 6242 for (k = 0; k < dof; ++k) { 6243 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6244 a[k] += values[off+dof-k-1]; 6245 } 6246 } 6247 } 6248 } 6249 } 6250 PetscCall(VecRestoreArray(v, &array)); 6251 PetscFunctionReturn(0); 6252 } 6253 6254 /*@C 6255 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6256 6257 Not collective 6258 6259 Input Parameters: 6260 + dm - The DM 6261 . section - The section describing the layout in v, or NULL to use the default section 6262 . v - The local vector 6263 . point - The point in the DM 6264 . values - The array of values 6265 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6266 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6267 6268 Fortran Notes: 6269 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6270 6271 Level: intermediate 6272 6273 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6274 @*/ 6275 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6276 { 6277 PetscSection clSection; 6278 IS clPoints; 6279 PetscScalar *array; 6280 PetscInt *points = NULL; 6281 const PetscInt *clp, *clperm = NULL; 6282 PetscInt depth, numFields, numPoints, p, clsize; 6283 6284 PetscFunctionBeginHot; 6285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6286 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6287 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6288 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6289 PetscCall(DMPlexGetDepth(dm, &depth)); 6290 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6291 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6292 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6293 PetscFunctionReturn(0); 6294 } 6295 /* Get points */ 6296 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6297 for (clsize=0,p=0; p<numPoints; p++) { 6298 PetscInt dof; 6299 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6300 clsize += dof; 6301 } 6302 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6303 /* Get array */ 6304 PetscCall(VecGetArray(v, &array)); 6305 /* Get values */ 6306 if (numFields > 0) { 6307 PetscInt offset = 0, f; 6308 for (f = 0; f < numFields; ++f) { 6309 const PetscInt **perms = NULL; 6310 const PetscScalar **flips = NULL; 6311 6312 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6313 switch (mode) { 6314 case INSERT_VALUES: 6315 for (p = 0; p < numPoints; p++) { 6316 const PetscInt point = points[2*p]; 6317 const PetscInt *perm = perms ? perms[p] : NULL; 6318 const PetscScalar *flip = flips ? flips[p] : NULL; 6319 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6320 } break; 6321 case INSERT_ALL_VALUES: 6322 for (p = 0; p < numPoints; p++) { 6323 const PetscInt point = points[2*p]; 6324 const PetscInt *perm = perms ? perms[p] : NULL; 6325 const PetscScalar *flip = flips ? flips[p] : NULL; 6326 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6327 } break; 6328 case INSERT_BC_VALUES: 6329 for (p = 0; p < numPoints; p++) { 6330 const PetscInt point = points[2*p]; 6331 const PetscInt *perm = perms ? perms[p] : NULL; 6332 const PetscScalar *flip = flips ? flips[p] : NULL; 6333 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6334 } break; 6335 case ADD_VALUES: 6336 for (p = 0; p < numPoints; p++) { 6337 const PetscInt point = points[2*p]; 6338 const PetscInt *perm = perms ? perms[p] : NULL; 6339 const PetscScalar *flip = flips ? flips[p] : NULL; 6340 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6341 } break; 6342 case ADD_ALL_VALUES: 6343 for (p = 0; p < numPoints; p++) { 6344 const PetscInt point = points[2*p]; 6345 const PetscInt *perm = perms ? perms[p] : NULL; 6346 const PetscScalar *flip = flips ? flips[p] : NULL; 6347 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6348 } break; 6349 case ADD_BC_VALUES: 6350 for (p = 0; p < numPoints; p++) { 6351 const PetscInt point = points[2*p]; 6352 const PetscInt *perm = perms ? perms[p] : NULL; 6353 const PetscScalar *flip = flips ? flips[p] : NULL; 6354 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6355 } break; 6356 default: 6357 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6358 } 6359 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6360 } 6361 } else { 6362 PetscInt dof, off; 6363 const PetscInt **perms = NULL; 6364 const PetscScalar **flips = NULL; 6365 6366 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6367 switch (mode) { 6368 case INSERT_VALUES: 6369 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6370 const PetscInt point = points[2*p]; 6371 const PetscInt *perm = perms ? perms[p] : NULL; 6372 const PetscScalar *flip = flips ? flips[p] : NULL; 6373 PetscCall(PetscSectionGetDof(section, point, &dof)); 6374 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6375 } break; 6376 case INSERT_ALL_VALUES: 6377 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6378 const PetscInt point = points[2*p]; 6379 const PetscInt *perm = perms ? perms[p] : NULL; 6380 const PetscScalar *flip = flips ? flips[p] : NULL; 6381 PetscCall(PetscSectionGetDof(section, point, &dof)); 6382 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6383 } break; 6384 case INSERT_BC_VALUES: 6385 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6386 const PetscInt point = points[2*p]; 6387 const PetscInt *perm = perms ? perms[p] : NULL; 6388 const PetscScalar *flip = flips ? flips[p] : NULL; 6389 PetscCall(PetscSectionGetDof(section, point, &dof)); 6390 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6391 } break; 6392 case ADD_VALUES: 6393 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6394 const PetscInt point = points[2*p]; 6395 const PetscInt *perm = perms ? perms[p] : NULL; 6396 const PetscScalar *flip = flips ? flips[p] : NULL; 6397 PetscCall(PetscSectionGetDof(section, point, &dof)); 6398 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6399 } break; 6400 case ADD_ALL_VALUES: 6401 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6402 const PetscInt point = points[2*p]; 6403 const PetscInt *perm = perms ? perms[p] : NULL; 6404 const PetscScalar *flip = flips ? flips[p] : NULL; 6405 PetscCall(PetscSectionGetDof(section, point, &dof)); 6406 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6407 } break; 6408 case ADD_BC_VALUES: 6409 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6410 const PetscInt point = points[2*p]; 6411 const PetscInt *perm = perms ? perms[p] : NULL; 6412 const PetscScalar *flip = flips ? flips[p] : NULL; 6413 PetscCall(PetscSectionGetDof(section, point, &dof)); 6414 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6415 } break; 6416 default: 6417 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6418 } 6419 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6420 } 6421 /* Cleanup points */ 6422 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6423 /* Cleanup array */ 6424 PetscCall(VecRestoreArray(v, &array)); 6425 PetscFunctionReturn(0); 6426 } 6427 6428 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6429 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6430 { 6431 PetscFunctionBegin; 6432 if (label) { 6433 PetscInt val, fdof; 6434 6435 /* There is a problem with this: 6436 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6437 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6438 Thus I am only going to check val != -1, not val != labelId 6439 */ 6440 PetscCall(DMLabelGetValue(label, point, &val)); 6441 if (val < 0) { 6442 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6443 *offset += fdof; 6444 PetscFunctionReturn(1); 6445 } 6446 } 6447 PetscFunctionReturn(0); 6448 } 6449 6450 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6451 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) 6452 { 6453 PetscSection clSection; 6454 IS clPoints; 6455 PetscScalar *array; 6456 PetscInt *points = NULL; 6457 const PetscInt *clp; 6458 PetscInt numFields, numPoints, p; 6459 PetscInt offset = 0, f; 6460 6461 PetscFunctionBeginHot; 6462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6463 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6464 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6465 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6466 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6467 /* Get points */ 6468 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6469 /* Get array */ 6470 PetscCall(VecGetArray(v, &array)); 6471 /* Get values */ 6472 for (f = 0; f < numFields; ++f) { 6473 const PetscInt **perms = NULL; 6474 const PetscScalar **flips = NULL; 6475 6476 if (!fieldActive[f]) { 6477 for (p = 0; p < numPoints*2; p += 2) { 6478 PetscInt fdof; 6479 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6480 offset += fdof; 6481 } 6482 continue; 6483 } 6484 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6485 switch (mode) { 6486 case INSERT_VALUES: 6487 for (p = 0; p < numPoints; p++) { 6488 const PetscInt point = points[2*p]; 6489 const PetscInt *perm = perms ? perms[p] : NULL; 6490 const PetscScalar *flip = flips ? flips[p] : NULL; 6491 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6492 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6493 } break; 6494 case INSERT_ALL_VALUES: 6495 for (p = 0; p < numPoints; p++) { 6496 const PetscInt point = points[2*p]; 6497 const PetscInt *perm = perms ? perms[p] : NULL; 6498 const PetscScalar *flip = flips ? flips[p] : NULL; 6499 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6500 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6501 } break; 6502 case INSERT_BC_VALUES: 6503 for (p = 0; p < numPoints; p++) { 6504 const PetscInt point = points[2*p]; 6505 const PetscInt *perm = perms ? perms[p] : NULL; 6506 const PetscScalar *flip = flips ? flips[p] : NULL; 6507 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6508 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6509 } break; 6510 case ADD_VALUES: 6511 for (p = 0; p < numPoints; p++) { 6512 const PetscInt point = points[2*p]; 6513 const PetscInt *perm = perms ? perms[p] : NULL; 6514 const PetscScalar *flip = flips ? flips[p] : NULL; 6515 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6516 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6517 } break; 6518 case ADD_ALL_VALUES: 6519 for (p = 0; p < numPoints; p++) { 6520 const PetscInt point = points[2*p]; 6521 const PetscInt *perm = perms ? perms[p] : NULL; 6522 const PetscScalar *flip = flips ? flips[p] : NULL; 6523 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6524 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6525 } break; 6526 default: 6527 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6528 } 6529 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6530 } 6531 /* Cleanup points */ 6532 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6533 /* Cleanup array */ 6534 PetscCall(VecRestoreArray(v, &array)); 6535 PetscFunctionReturn(0); 6536 } 6537 6538 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6539 { 6540 PetscMPIInt rank; 6541 PetscInt i, j; 6542 6543 PetscFunctionBegin; 6544 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6545 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6546 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6547 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6548 numCIndices = numCIndices ? numCIndices : numRIndices; 6549 if (!values) PetscFunctionReturn(0); 6550 for (i = 0; i < numRIndices; i++) { 6551 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6552 for (j = 0; j < numCIndices; j++) { 6553 #if defined(PETSC_USE_COMPLEX) 6554 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6555 #else 6556 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6557 #endif 6558 } 6559 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6560 } 6561 PetscFunctionReturn(0); 6562 } 6563 6564 /* 6565 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6566 6567 Input Parameters: 6568 + section - The section for this data layout 6569 . islocal - Is the section (and thus indices being requested) local or global? 6570 . point - The point contributing dofs with these indices 6571 . off - The global offset of this point 6572 . loff - The local offset of each field 6573 . setBC - The flag determining whether to include indices of boundary values 6574 . perm - A permutation of the dofs on this point, or NULL 6575 - indperm - A permutation of the entire indices array, or NULL 6576 6577 Output Parameter: 6578 . indices - Indices for dofs on this point 6579 6580 Level: developer 6581 6582 Note: The indices could be local or global, depending on the value of 'off'. 6583 */ 6584 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6585 { 6586 PetscInt dof; /* The number of unknowns on this point */ 6587 PetscInt cdof; /* The number of constraints on this point */ 6588 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6589 PetscInt cind = 0, k; 6590 6591 PetscFunctionBegin; 6592 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6593 PetscCall(PetscSectionGetDof(section, point, &dof)); 6594 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6595 if (!cdof || setBC) { 6596 for (k = 0; k < dof; ++k) { 6597 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6598 const PetscInt ind = indperm ? indperm[preind] : preind; 6599 6600 indices[ind] = off + k; 6601 } 6602 } else { 6603 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6604 for (k = 0; k < dof; ++k) { 6605 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6606 const PetscInt ind = indperm ? indperm[preind] : preind; 6607 6608 if ((cind < cdof) && (k == cdofs[cind])) { 6609 /* Insert check for returning constrained indices */ 6610 indices[ind] = -(off+k+1); 6611 ++cind; 6612 } else { 6613 indices[ind] = off + k - (islocal ? 0 : cind); 6614 } 6615 } 6616 } 6617 *loff += dof; 6618 PetscFunctionReturn(0); 6619 } 6620 6621 /* 6622 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6623 6624 Input Parameters: 6625 + section - a section (global or local) 6626 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6627 . point - point within section 6628 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6629 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6630 . setBC - identify constrained (boundary condition) points via involution. 6631 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6632 . permsoff - offset 6633 - indperm - index permutation 6634 6635 Output Parameter: 6636 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6637 . indices - array to hold indices (as defined by section) of each dof associated with point 6638 6639 Notes: 6640 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6641 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6642 in the local vector. 6643 6644 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6645 significant). It is invalid to call with a global section and setBC=true. 6646 6647 Developer Note: 6648 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6649 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6650 offset could be obtained from the section instead of passing it explicitly as we do now. 6651 6652 Example: 6653 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6654 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6655 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6656 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. 6657 6658 Level: developer 6659 */ 6660 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[]) 6661 { 6662 PetscInt numFields, foff, f; 6663 6664 PetscFunctionBegin; 6665 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6666 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6667 for (f = 0, foff = 0; f < numFields; ++f) { 6668 PetscInt fdof, cfdof; 6669 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6670 PetscInt cind = 0, b; 6671 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6672 6673 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6674 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6675 if (!cfdof || setBC) { 6676 for (b = 0; b < fdof; ++b) { 6677 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6678 const PetscInt ind = indperm ? indperm[preind] : preind; 6679 6680 indices[ind] = off+foff+b; 6681 } 6682 } else { 6683 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6684 for (b = 0; b < fdof; ++b) { 6685 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6686 const PetscInt ind = indperm ? indperm[preind] : preind; 6687 6688 if ((cind < cfdof) && (b == fcdofs[cind])) { 6689 indices[ind] = -(off+foff+b+1); 6690 ++cind; 6691 } else { 6692 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6693 } 6694 } 6695 } 6696 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6697 foffs[f] += fdof; 6698 } 6699 PetscFunctionReturn(0); 6700 } 6701 6702 /* 6703 This version believes the globalSection offsets for each field, rather than just the point offset 6704 6705 . foffs - The offset into 'indices' for each field, since it is segregated by field 6706 6707 Notes: 6708 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6709 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6710 */ 6711 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6712 { 6713 PetscInt numFields, foff, f; 6714 6715 PetscFunctionBegin; 6716 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6717 for (f = 0; f < numFields; ++f) { 6718 PetscInt fdof, cfdof; 6719 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6720 PetscInt cind = 0, b; 6721 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6722 6723 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6724 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6725 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6726 if (!cfdof) { 6727 for (b = 0; b < fdof; ++b) { 6728 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6729 const PetscInt ind = indperm ? indperm[preind] : preind; 6730 6731 indices[ind] = foff+b; 6732 } 6733 } else { 6734 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6735 for (b = 0; b < fdof; ++b) { 6736 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6737 const PetscInt ind = indperm ? indperm[preind] : preind; 6738 6739 if ((cind < cfdof) && (b == fcdofs[cind])) { 6740 indices[ind] = -(foff+b+1); 6741 ++cind; 6742 } else { 6743 indices[ind] = foff+b-cind; 6744 } 6745 } 6746 } 6747 foffs[f] += fdof; 6748 } 6749 PetscFunctionReturn(0); 6750 } 6751 6752 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) 6753 { 6754 Mat cMat; 6755 PetscSection aSec, cSec; 6756 IS aIS; 6757 PetscInt aStart = -1, aEnd = -1; 6758 const PetscInt *anchors; 6759 PetscInt numFields, f, p, q, newP = 0; 6760 PetscInt newNumPoints = 0, newNumIndices = 0; 6761 PetscInt *newPoints, *indices, *newIndices; 6762 PetscInt maxAnchor, maxDof; 6763 PetscInt newOffsets[32]; 6764 PetscInt *pointMatOffsets[32]; 6765 PetscInt *newPointOffsets[32]; 6766 PetscScalar *pointMat[32]; 6767 PetscScalar *newValues=NULL,*tmpValues; 6768 PetscBool anyConstrained = PETSC_FALSE; 6769 6770 PetscFunctionBegin; 6771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6772 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6773 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6774 6775 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6776 /* if there are point-to-point constraints */ 6777 if (aSec) { 6778 PetscCall(PetscArrayzero(newOffsets, 32)); 6779 PetscCall(ISGetIndices(aIS,&anchors)); 6780 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6781 /* figure out how many points are going to be in the new element matrix 6782 * (we allow double counting, because it's all just going to be summed 6783 * into the global matrix anyway) */ 6784 for (p = 0; p < 2*numPoints; p+=2) { 6785 PetscInt b = points[p]; 6786 PetscInt bDof = 0, bSecDof; 6787 6788 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6789 if (!bSecDof) { 6790 continue; 6791 } 6792 if (b >= aStart && b < aEnd) { 6793 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6794 } 6795 if (bDof) { 6796 /* this point is constrained */ 6797 /* it is going to be replaced by its anchors */ 6798 PetscInt bOff, q; 6799 6800 anyConstrained = PETSC_TRUE; 6801 newNumPoints += bDof; 6802 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6803 for (q = 0; q < bDof; q++) { 6804 PetscInt a = anchors[bOff + q]; 6805 PetscInt aDof; 6806 6807 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6808 newNumIndices += aDof; 6809 for (f = 0; f < numFields; ++f) { 6810 PetscInt fDof; 6811 6812 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6813 newOffsets[f+1] += fDof; 6814 } 6815 } 6816 } 6817 else { 6818 /* this point is not constrained */ 6819 newNumPoints++; 6820 newNumIndices += bSecDof; 6821 for (f = 0; f < numFields; ++f) { 6822 PetscInt fDof; 6823 6824 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6825 newOffsets[f+1] += fDof; 6826 } 6827 } 6828 } 6829 } 6830 if (!anyConstrained) { 6831 if (outNumPoints) *outNumPoints = 0; 6832 if (outNumIndices) *outNumIndices = 0; 6833 if (outPoints) *outPoints = NULL; 6834 if (outValues) *outValues = NULL; 6835 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6836 PetscFunctionReturn(0); 6837 } 6838 6839 if (outNumPoints) *outNumPoints = newNumPoints; 6840 if (outNumIndices) *outNumIndices = newNumIndices; 6841 6842 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6843 6844 if (!outPoints && !outValues) { 6845 if (offsets) { 6846 for (f = 0; f <= numFields; f++) { 6847 offsets[f] = newOffsets[f]; 6848 } 6849 } 6850 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6851 PetscFunctionReturn(0); 6852 } 6853 6854 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6855 6856 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6857 6858 /* workspaces */ 6859 if (numFields) { 6860 for (f = 0; f < numFields; f++) { 6861 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6862 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6863 } 6864 } 6865 else { 6866 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6867 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6868 } 6869 6870 /* get workspaces for the point-to-point matrices */ 6871 if (numFields) { 6872 PetscInt totalOffset, totalMatOffset; 6873 6874 for (p = 0; p < numPoints; p++) { 6875 PetscInt b = points[2*p]; 6876 PetscInt bDof = 0, bSecDof; 6877 6878 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6879 if (!bSecDof) { 6880 for (f = 0; f < numFields; f++) { 6881 newPointOffsets[f][p + 1] = 0; 6882 pointMatOffsets[f][p + 1] = 0; 6883 } 6884 continue; 6885 } 6886 if (b >= aStart && b < aEnd) { 6887 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6888 } 6889 if (bDof) { 6890 for (f = 0; f < numFields; f++) { 6891 PetscInt fDof, q, bOff, allFDof = 0; 6892 6893 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6894 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6895 for (q = 0; q < bDof; q++) { 6896 PetscInt a = anchors[bOff + q]; 6897 PetscInt aFDof; 6898 6899 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6900 allFDof += aFDof; 6901 } 6902 newPointOffsets[f][p+1] = allFDof; 6903 pointMatOffsets[f][p+1] = fDof * allFDof; 6904 } 6905 } 6906 else { 6907 for (f = 0; f < numFields; f++) { 6908 PetscInt fDof; 6909 6910 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6911 newPointOffsets[f][p+1] = fDof; 6912 pointMatOffsets[f][p+1] = 0; 6913 } 6914 } 6915 } 6916 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6917 newPointOffsets[f][0] = totalOffset; 6918 pointMatOffsets[f][0] = totalMatOffset; 6919 for (p = 0; p < numPoints; p++) { 6920 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6921 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6922 } 6923 totalOffset = newPointOffsets[f][numPoints]; 6924 totalMatOffset = pointMatOffsets[f][numPoints]; 6925 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6926 } 6927 } 6928 else { 6929 for (p = 0; p < numPoints; p++) { 6930 PetscInt b = points[2*p]; 6931 PetscInt bDof = 0, bSecDof; 6932 6933 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6934 if (!bSecDof) { 6935 newPointOffsets[0][p + 1] = 0; 6936 pointMatOffsets[0][p + 1] = 0; 6937 continue; 6938 } 6939 if (b >= aStart && b < aEnd) { 6940 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6941 } 6942 if (bDof) { 6943 PetscInt bOff, q, allDof = 0; 6944 6945 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6946 for (q = 0; q < bDof; q++) { 6947 PetscInt a = anchors[bOff + q], aDof; 6948 6949 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6950 allDof += aDof; 6951 } 6952 newPointOffsets[0][p+1] = allDof; 6953 pointMatOffsets[0][p+1] = bSecDof * allDof; 6954 } 6955 else { 6956 newPointOffsets[0][p+1] = bSecDof; 6957 pointMatOffsets[0][p+1] = 0; 6958 } 6959 } 6960 newPointOffsets[0][0] = 0; 6961 pointMatOffsets[0][0] = 0; 6962 for (p = 0; p < numPoints; p++) { 6963 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6964 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6965 } 6966 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6967 } 6968 6969 /* output arrays */ 6970 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6971 6972 /* get the point-to-point matrices; construct newPoints */ 6973 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6974 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6975 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6976 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6977 if (numFields) { 6978 for (p = 0, newP = 0; p < numPoints; p++) { 6979 PetscInt b = points[2*p]; 6980 PetscInt o = points[2*p+1]; 6981 PetscInt bDof = 0, bSecDof; 6982 6983 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6984 if (!bSecDof) { 6985 continue; 6986 } 6987 if (b >= aStart && b < aEnd) { 6988 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6989 } 6990 if (bDof) { 6991 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6992 6993 fStart[0] = 0; 6994 fEnd[0] = 0; 6995 for (f = 0; f < numFields; f++) { 6996 PetscInt fDof; 6997 6998 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6999 fStart[f+1] = fStart[f] + fDof; 7000 fEnd[f+1] = fStart[f+1]; 7001 } 7002 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7003 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7004 7005 fAnchorStart[0] = 0; 7006 fAnchorEnd[0] = 0; 7007 for (f = 0; f < numFields; f++) { 7008 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7009 7010 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7011 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7012 } 7013 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7014 for (q = 0; q < bDof; q++) { 7015 PetscInt a = anchors[bOff + q], aOff; 7016 7017 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7018 newPoints[2*(newP + q)] = a; 7019 newPoints[2*(newP + q) + 1] = 0; 7020 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7021 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7022 } 7023 newP += bDof; 7024 7025 if (outValues) { 7026 /* get the point-to-point submatrix */ 7027 for (f = 0; f < numFields; f++) { 7028 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7029 } 7030 } 7031 } 7032 else { 7033 newPoints[2 * newP] = b; 7034 newPoints[2 * newP + 1] = o; 7035 newP++; 7036 } 7037 } 7038 } else { 7039 for (p = 0; p < numPoints; p++) { 7040 PetscInt b = points[2*p]; 7041 PetscInt o = points[2*p+1]; 7042 PetscInt bDof = 0, bSecDof; 7043 7044 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7045 if (!bSecDof) { 7046 continue; 7047 } 7048 if (b >= aStart && b < aEnd) { 7049 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7050 } 7051 if (bDof) { 7052 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7053 7054 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7055 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7056 7057 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7058 for (q = 0; q < bDof; q++) { 7059 PetscInt a = anchors[bOff + q], aOff; 7060 7061 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7062 7063 newPoints[2*(newP + q)] = a; 7064 newPoints[2*(newP + q) + 1] = 0; 7065 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7066 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7067 } 7068 newP += bDof; 7069 7070 /* get the point-to-point submatrix */ 7071 if (outValues) { 7072 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7073 } 7074 } 7075 else { 7076 newPoints[2 * newP] = b; 7077 newPoints[2 * newP + 1] = o; 7078 newP++; 7079 } 7080 } 7081 } 7082 7083 if (outValues) { 7084 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7085 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7086 /* multiply constraints on the right */ 7087 if (numFields) { 7088 for (f = 0; f < numFields; f++) { 7089 PetscInt oldOff = offsets[f]; 7090 7091 for (p = 0; p < numPoints; p++) { 7092 PetscInt cStart = newPointOffsets[f][p]; 7093 PetscInt b = points[2 * p]; 7094 PetscInt c, r, k; 7095 PetscInt dof; 7096 7097 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7098 if (!dof) { 7099 continue; 7100 } 7101 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7102 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7103 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7104 7105 for (r = 0; r < numIndices; r++) { 7106 for (c = 0; c < nCols; c++) { 7107 for (k = 0; k < dof; k++) { 7108 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7109 } 7110 } 7111 } 7112 } 7113 else { 7114 /* copy this column as is */ 7115 for (r = 0; r < numIndices; r++) { 7116 for (c = 0; c < dof; c++) { 7117 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7118 } 7119 } 7120 } 7121 oldOff += dof; 7122 } 7123 } 7124 } 7125 else { 7126 PetscInt oldOff = 0; 7127 for (p = 0; p < numPoints; p++) { 7128 PetscInt cStart = newPointOffsets[0][p]; 7129 PetscInt b = points[2 * p]; 7130 PetscInt c, r, k; 7131 PetscInt dof; 7132 7133 PetscCall(PetscSectionGetDof(section,b,&dof)); 7134 if (!dof) { 7135 continue; 7136 } 7137 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7138 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7139 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7140 7141 for (r = 0; r < numIndices; r++) { 7142 for (c = 0; c < nCols; c++) { 7143 for (k = 0; k < dof; k++) { 7144 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7145 } 7146 } 7147 } 7148 } 7149 else { 7150 /* copy this column as is */ 7151 for (r = 0; r < numIndices; r++) { 7152 for (c = 0; c < dof; c++) { 7153 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7154 } 7155 } 7156 } 7157 oldOff += dof; 7158 } 7159 } 7160 7161 if (multiplyLeft) { 7162 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7163 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7164 /* multiply constraints transpose on the left */ 7165 if (numFields) { 7166 for (f = 0; f < numFields; f++) { 7167 PetscInt oldOff = offsets[f]; 7168 7169 for (p = 0; p < numPoints; p++) { 7170 PetscInt rStart = newPointOffsets[f][p]; 7171 PetscInt b = points[2 * p]; 7172 PetscInt c, r, k; 7173 PetscInt dof; 7174 7175 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7176 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7177 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7178 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7179 7180 for (r = 0; r < nRows; r++) { 7181 for (c = 0; c < newNumIndices; c++) { 7182 for (k = 0; k < dof; k++) { 7183 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7184 } 7185 } 7186 } 7187 } 7188 else { 7189 /* copy this row as is */ 7190 for (r = 0; r < dof; r++) { 7191 for (c = 0; c < newNumIndices; c++) { 7192 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7193 } 7194 } 7195 } 7196 oldOff += dof; 7197 } 7198 } 7199 } 7200 else { 7201 PetscInt oldOff = 0; 7202 7203 for (p = 0; p < numPoints; p++) { 7204 PetscInt rStart = newPointOffsets[0][p]; 7205 PetscInt b = points[2 * p]; 7206 PetscInt c, r, k; 7207 PetscInt dof; 7208 7209 PetscCall(PetscSectionGetDof(section,b,&dof)); 7210 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7211 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7212 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7213 7214 for (r = 0; r < nRows; r++) { 7215 for (c = 0; c < newNumIndices; c++) { 7216 for (k = 0; k < dof; k++) { 7217 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7218 } 7219 } 7220 } 7221 } 7222 else { 7223 /* copy this row as is */ 7224 for (r = 0; r < dof; r++) { 7225 for (c = 0; c < newNumIndices; c++) { 7226 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7227 } 7228 } 7229 } 7230 oldOff += dof; 7231 } 7232 } 7233 7234 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7235 } 7236 else { 7237 newValues = tmpValues; 7238 } 7239 } 7240 7241 /* clean up */ 7242 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7243 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7244 7245 if (numFields) { 7246 for (f = 0; f < numFields; f++) { 7247 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7248 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7249 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7250 } 7251 } 7252 else { 7253 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7254 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7255 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7256 } 7257 PetscCall(ISRestoreIndices(aIS,&anchors)); 7258 7259 /* output */ 7260 if (outPoints) { 7261 *outPoints = newPoints; 7262 } 7263 else { 7264 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7265 } 7266 if (outValues) { 7267 *outValues = newValues; 7268 } 7269 for (f = 0; f <= numFields; f++) { 7270 offsets[f] = newOffsets[f]; 7271 } 7272 PetscFunctionReturn(0); 7273 } 7274 7275 /*@C 7276 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7277 7278 Not collective 7279 7280 Input Parameters: 7281 + dm - The DM 7282 . section - The PetscSection describing the points (a local section) 7283 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7284 . point - The point defining the closure 7285 - useClPerm - Use the closure point permutation if available 7286 7287 Output Parameters: 7288 + numIndices - The number of dof indices in the closure of point with the input sections 7289 . indices - The dof indices 7290 . outOffsets - Array to write the field offsets into, or NULL 7291 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7292 7293 Notes: 7294 Must call DMPlexRestoreClosureIndices() to free allocated memory 7295 7296 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7297 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7298 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7299 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7300 indices (with the above semantics) are implied. 7301 7302 Level: advanced 7303 7304 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7305 @*/ 7306 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7307 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7308 { 7309 /* Closure ordering */ 7310 PetscSection clSection; 7311 IS clPoints; 7312 const PetscInt *clp; 7313 PetscInt *points; 7314 const PetscInt *clperm = NULL; 7315 /* Dof permutation and sign flips */ 7316 const PetscInt **perms[32] = {NULL}; 7317 const PetscScalar **flips[32] = {NULL}; 7318 PetscScalar *valCopy = NULL; 7319 /* Hanging node constraints */ 7320 PetscInt *pointsC = NULL; 7321 PetscScalar *valuesC = NULL; 7322 PetscInt NclC, NiC; 7323 7324 PetscInt *idx; 7325 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7326 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7327 7328 PetscFunctionBeginHot; 7329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7330 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7331 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7332 if (numIndices) PetscValidIntPointer(numIndices, 6); 7333 if (indices) PetscValidPointer(indices, 7); 7334 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7335 if (values) PetscValidPointer(values, 9); 7336 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7337 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7338 PetscCall(PetscArrayzero(offsets, 32)); 7339 /* 1) Get points in closure */ 7340 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7341 if (useClPerm) { 7342 PetscInt depth, clsize; 7343 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7344 for (clsize=0,p=0; p<Ncl; p++) { 7345 PetscInt dof; 7346 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7347 clsize += dof; 7348 } 7349 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7350 } 7351 /* 2) Get number of indices on these points and field offsets from section */ 7352 for (p = 0; p < Ncl*2; p += 2) { 7353 PetscInt dof, fdof; 7354 7355 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7356 for (f = 0; f < Nf; ++f) { 7357 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7358 offsets[f+1] += fdof; 7359 } 7360 Ni += dof; 7361 } 7362 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7363 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7364 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7365 for (f = 0; f < PetscMax(1, Nf); ++f) { 7366 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7367 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7368 /* may need to apply sign changes to the element matrix */ 7369 if (values && flips[f]) { 7370 PetscInt foffset = offsets[f]; 7371 7372 for (p = 0; p < Ncl; ++p) { 7373 PetscInt pnt = points[2*p], fdof; 7374 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7375 7376 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7377 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7378 if (flip) { 7379 PetscInt i, j, k; 7380 7381 if (!valCopy) { 7382 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7383 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7384 *values = valCopy; 7385 } 7386 for (i = 0; i < fdof; ++i) { 7387 PetscScalar fval = flip[i]; 7388 7389 for (k = 0; k < Ni; ++k) { 7390 valCopy[Ni * (foffset + i) + k] *= fval; 7391 valCopy[Ni * k + (foffset + i)] *= fval; 7392 } 7393 } 7394 } 7395 foffset += fdof; 7396 } 7397 } 7398 } 7399 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7400 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7401 if (NclC) { 7402 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7403 for (f = 0; f < PetscMax(1, Nf); ++f) { 7404 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7405 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7406 } 7407 for (f = 0; f < PetscMax(1, Nf); ++f) { 7408 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7409 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7410 } 7411 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7412 Ncl = NclC; 7413 Ni = NiC; 7414 points = pointsC; 7415 if (values) *values = valuesC; 7416 } 7417 /* 5) Calculate indices */ 7418 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7419 if (Nf) { 7420 PetscInt idxOff; 7421 PetscBool useFieldOffsets; 7422 7423 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7424 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7425 if (useFieldOffsets) { 7426 for (p = 0; p < Ncl; ++p) { 7427 const PetscInt pnt = points[p*2]; 7428 7429 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7430 } 7431 } else { 7432 for (p = 0; p < Ncl; ++p) { 7433 const PetscInt pnt = points[p*2]; 7434 7435 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7436 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7437 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7438 * global section. */ 7439 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7440 } 7441 } 7442 } else { 7443 PetscInt off = 0, idxOff; 7444 7445 for (p = 0; p < Ncl; ++p) { 7446 const PetscInt pnt = points[p*2]; 7447 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7448 7449 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7450 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7451 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7452 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7453 } 7454 } 7455 /* 6) Cleanup */ 7456 for (f = 0; f < PetscMax(1, Nf); ++f) { 7457 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7458 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7459 } 7460 if (NclC) { 7461 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7462 } else { 7463 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7464 } 7465 7466 if (numIndices) *numIndices = Ni; 7467 if (indices) *indices = idx; 7468 PetscFunctionReturn(0); 7469 } 7470 7471 /*@C 7472 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7473 7474 Not collective 7475 7476 Input Parameters: 7477 + dm - The DM 7478 . section - The PetscSection describing the points (a local section) 7479 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7480 . point - The point defining the closure 7481 - useClPerm - Use the closure point permutation if available 7482 7483 Output Parameters: 7484 + numIndices - The number of dof indices in the closure of point with the input sections 7485 . indices - The dof indices 7486 . outOffsets - Array to write the field offsets into, or NULL 7487 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7488 7489 Notes: 7490 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7491 7492 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7493 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7494 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7495 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7496 indices (with the above semantics) are implied. 7497 7498 Level: advanced 7499 7500 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7501 @*/ 7502 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7503 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7504 { 7505 PetscFunctionBegin; 7506 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7507 PetscValidPointer(indices, 7); 7508 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7509 PetscFunctionReturn(0); 7510 } 7511 7512 /*@C 7513 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7514 7515 Not collective 7516 7517 Input Parameters: 7518 + dm - The DM 7519 . section - The section describing the layout in v, or NULL to use the default section 7520 . globalSection - The section describing the layout in v, or NULL to use the default global section 7521 . A - The matrix 7522 . point - The point in the DM 7523 . values - The array of values 7524 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7525 7526 Fortran Notes: 7527 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7528 7529 Level: intermediate 7530 7531 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7532 @*/ 7533 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7534 { 7535 DM_Plex *mesh = (DM_Plex*) dm->data; 7536 PetscInt *indices; 7537 PetscInt numIndices; 7538 const PetscScalar *valuesOrig = values; 7539 PetscErrorCode ierr; 7540 7541 PetscFunctionBegin; 7542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7543 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7544 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7545 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7546 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7547 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7548 7549 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7550 7551 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7552 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7553 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7554 if (ierr) { 7555 PetscMPIInt rank; 7556 7557 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7558 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7559 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7560 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7561 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7562 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7563 } 7564 if (mesh->printFEM > 1) { 7565 PetscInt i; 7566 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7567 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7568 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7569 } 7570 7571 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7572 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7573 PetscFunctionReturn(0); 7574 } 7575 7576 /*@C 7577 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7578 7579 Not collective 7580 7581 Input Parameters: 7582 + dmRow - The DM for the row fields 7583 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7584 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7585 . dmCol - The DM for the column fields 7586 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7587 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7588 . A - The matrix 7589 . point - The point in the DMs 7590 . values - The array of values 7591 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7592 7593 Level: intermediate 7594 7595 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7596 @*/ 7597 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7598 { 7599 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7600 PetscInt *indicesRow, *indicesCol; 7601 PetscInt numIndicesRow, numIndicesCol; 7602 const PetscScalar *valuesOrig = values; 7603 PetscErrorCode ierr; 7604 7605 PetscFunctionBegin; 7606 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7607 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7608 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7609 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7610 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7611 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7612 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7613 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7614 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7615 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7616 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7617 7618 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7619 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7620 7621 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7622 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7623 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7624 if (ierr) { 7625 PetscMPIInt rank; 7626 7627 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7628 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7629 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7630 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7631 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7632 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7633 } 7634 7635 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7636 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7637 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7638 PetscFunctionReturn(0); 7639 } 7640 7641 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7642 { 7643 DM_Plex *mesh = (DM_Plex*) dmf->data; 7644 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7645 PetscInt *cpoints = NULL; 7646 PetscInt *findices, *cindices; 7647 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7648 PetscInt foffsets[32], coffsets[32]; 7649 DMPolytopeType ct; 7650 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7651 PetscErrorCode ierr; 7652 7653 PetscFunctionBegin; 7654 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7655 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7656 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7657 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7658 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7659 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7660 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7661 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7662 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7663 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7664 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7665 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7666 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7667 PetscCall(PetscArrayzero(foffsets, 32)); 7668 PetscCall(PetscArrayzero(coffsets, 32)); 7669 /* Column indices */ 7670 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7671 maxFPoints = numCPoints; 7672 /* Compress out points not in the section */ 7673 /* TODO: Squeeze out points with 0 dof as well */ 7674 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7675 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7676 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7677 cpoints[q*2] = cpoints[p]; 7678 cpoints[q*2+1] = cpoints[p+1]; 7679 ++q; 7680 } 7681 } 7682 numCPoints = q; 7683 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7684 PetscInt fdof; 7685 7686 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7687 if (!dof) continue; 7688 for (f = 0; f < numFields; ++f) { 7689 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7690 coffsets[f+1] += fdof; 7691 } 7692 numCIndices += dof; 7693 } 7694 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7695 /* Row indices */ 7696 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7697 { 7698 DMPlexTransform tr; 7699 DMPolytopeType *rct; 7700 PetscInt *rsize, *rcone, *rornt, Nt; 7701 7702 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7703 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7704 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7705 numSubcells = rsize[Nt-1]; 7706 PetscCall(DMPlexTransformDestroy(&tr)); 7707 } 7708 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7709 for (r = 0, q = 0; r < numSubcells; ++r) { 7710 /* TODO Map from coarse to fine cells */ 7711 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7712 /* Compress out points not in the section */ 7713 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7714 for (p = 0; p < numFPoints*2; p += 2) { 7715 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7716 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7717 if (!dof) continue; 7718 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7719 if (s < q) continue; 7720 ftotpoints[q*2] = fpoints[p]; 7721 ftotpoints[q*2+1] = fpoints[p+1]; 7722 ++q; 7723 } 7724 } 7725 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7726 } 7727 numFPoints = q; 7728 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7729 PetscInt fdof; 7730 7731 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7732 if (!dof) continue; 7733 for (f = 0; f < numFields; ++f) { 7734 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7735 foffsets[f+1] += fdof; 7736 } 7737 numFIndices += dof; 7738 } 7739 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7740 7741 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7742 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7743 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7744 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7745 if (numFields) { 7746 const PetscInt **permsF[32] = {NULL}; 7747 const PetscInt **permsC[32] = {NULL}; 7748 7749 for (f = 0; f < numFields; f++) { 7750 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7751 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7752 } 7753 for (p = 0; p < numFPoints; p++) { 7754 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7755 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7756 } 7757 for (p = 0; p < numCPoints; p++) { 7758 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7759 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7760 } 7761 for (f = 0; f < numFields; f++) { 7762 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7763 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7764 } 7765 } else { 7766 const PetscInt **permsF = NULL; 7767 const PetscInt **permsC = NULL; 7768 7769 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7770 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7771 for (p = 0, off = 0; p < numFPoints; p++) { 7772 const PetscInt *perm = permsF ? permsF[p] : NULL; 7773 7774 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7775 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7776 } 7777 for (p = 0, off = 0; p < numCPoints; p++) { 7778 const PetscInt *perm = permsC ? permsC[p] : NULL; 7779 7780 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7781 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7782 } 7783 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7784 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7785 } 7786 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7787 /* TODO: flips */ 7788 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7789 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7790 if (ierr) { 7791 PetscMPIInt rank; 7792 7793 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7794 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7795 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7796 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7797 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7798 } 7799 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7800 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7801 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7802 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7803 PetscFunctionReturn(0); 7804 } 7805 7806 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7807 { 7808 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7809 PetscInt *cpoints = NULL; 7810 PetscInt foffsets[32], coffsets[32]; 7811 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7812 DMPolytopeType ct; 7813 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7814 7815 PetscFunctionBegin; 7816 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7817 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7818 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7819 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7820 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7821 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7822 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7823 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7824 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7825 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7826 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7827 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7828 PetscCall(PetscArrayzero(foffsets, 32)); 7829 PetscCall(PetscArrayzero(coffsets, 32)); 7830 /* Column indices */ 7831 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7832 maxFPoints = numCPoints; 7833 /* Compress out points not in the section */ 7834 /* TODO: Squeeze out points with 0 dof as well */ 7835 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7836 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7837 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7838 cpoints[q*2] = cpoints[p]; 7839 cpoints[q*2+1] = cpoints[p+1]; 7840 ++q; 7841 } 7842 } 7843 numCPoints = q; 7844 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7845 PetscInt fdof; 7846 7847 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7848 if (!dof) continue; 7849 for (f = 0; f < numFields; ++f) { 7850 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7851 coffsets[f+1] += fdof; 7852 } 7853 numCIndices += dof; 7854 } 7855 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7856 /* Row indices */ 7857 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7858 { 7859 DMPlexTransform tr; 7860 DMPolytopeType *rct; 7861 PetscInt *rsize, *rcone, *rornt, Nt; 7862 7863 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7864 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7865 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7866 numSubcells = rsize[Nt-1]; 7867 PetscCall(DMPlexTransformDestroy(&tr)); 7868 } 7869 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7870 for (r = 0, q = 0; r < numSubcells; ++r) { 7871 /* TODO Map from coarse to fine cells */ 7872 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7873 /* Compress out points not in the section */ 7874 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7875 for (p = 0; p < numFPoints*2; p += 2) { 7876 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7877 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7878 if (!dof) continue; 7879 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7880 if (s < q) continue; 7881 ftotpoints[q*2] = fpoints[p]; 7882 ftotpoints[q*2+1] = fpoints[p+1]; 7883 ++q; 7884 } 7885 } 7886 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7887 } 7888 numFPoints = q; 7889 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7890 PetscInt fdof; 7891 7892 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7893 if (!dof) continue; 7894 for (f = 0; f < numFields; ++f) { 7895 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7896 foffsets[f+1] += fdof; 7897 } 7898 numFIndices += dof; 7899 } 7900 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7901 7902 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7903 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7904 if (numFields) { 7905 const PetscInt **permsF[32] = {NULL}; 7906 const PetscInt **permsC[32] = {NULL}; 7907 7908 for (f = 0; f < numFields; f++) { 7909 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7910 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7911 } 7912 for (p = 0; p < numFPoints; p++) { 7913 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7914 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7915 } 7916 for (p = 0; p < numCPoints; p++) { 7917 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7918 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7919 } 7920 for (f = 0; f < numFields; f++) { 7921 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7922 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7923 } 7924 } else { 7925 const PetscInt **permsF = NULL; 7926 const PetscInt **permsC = NULL; 7927 7928 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7929 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7930 for (p = 0, off = 0; p < numFPoints; p++) { 7931 const PetscInt *perm = permsF ? permsF[p] : NULL; 7932 7933 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7934 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7935 } 7936 for (p = 0, off = 0; p < numCPoints; p++) { 7937 const PetscInt *perm = permsC ? permsC[p] : NULL; 7938 7939 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7940 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7941 } 7942 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7943 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7944 } 7945 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7946 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7947 PetscFunctionReturn(0); 7948 } 7949 7950 /*@C 7951 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7952 7953 Input Parameter: 7954 . dm - The DMPlex object 7955 7956 Output Parameter: 7957 . cellHeight - The height of a cell 7958 7959 Level: developer 7960 7961 .seealso `DMPlexSetVTKCellHeight()` 7962 @*/ 7963 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7964 { 7965 DM_Plex *mesh = (DM_Plex*) dm->data; 7966 7967 PetscFunctionBegin; 7968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7969 PetscValidIntPointer(cellHeight, 2); 7970 *cellHeight = mesh->vtkCellHeight; 7971 PetscFunctionReturn(0); 7972 } 7973 7974 /*@C 7975 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7976 7977 Input Parameters: 7978 + dm - The DMPlex object 7979 - cellHeight - The height of a cell 7980 7981 Level: developer 7982 7983 .seealso `DMPlexGetVTKCellHeight()` 7984 @*/ 7985 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7986 { 7987 DM_Plex *mesh = (DM_Plex*) dm->data; 7988 7989 PetscFunctionBegin; 7990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7991 mesh->vtkCellHeight = cellHeight; 7992 PetscFunctionReturn(0); 7993 } 7994 7995 /*@ 7996 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7997 7998 Input Parameter: 7999 . dm - The DMPlex object 8000 8001 Output Parameters: 8002 + gcStart - The first ghost cell, or NULL 8003 - gcEnd - The upper bound on ghost cells, or NULL 8004 8005 Level: advanced 8006 8007 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8008 @*/ 8009 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8010 { 8011 DMLabel ctLabel; 8012 8013 PetscFunctionBegin; 8014 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8015 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8016 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8017 PetscFunctionReturn(0); 8018 } 8019 8020 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8021 { 8022 PetscSection section, globalSection; 8023 PetscInt *numbers, p; 8024 8025 PetscFunctionBegin; 8026 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8027 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8028 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8029 for (p = pStart; p < pEnd; ++p) { 8030 PetscCall(PetscSectionSetDof(section, p, 1)); 8031 } 8032 PetscCall(PetscSectionSetUp(section)); 8033 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8034 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8035 for (p = pStart; p < pEnd; ++p) { 8036 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8037 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8038 else numbers[p-pStart] += shift; 8039 } 8040 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8041 if (globalSize) { 8042 PetscLayout layout; 8043 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8044 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8045 PetscCall(PetscLayoutDestroy(&layout)); 8046 } 8047 PetscCall(PetscSectionDestroy(§ion)); 8048 PetscCall(PetscSectionDestroy(&globalSection)); 8049 PetscFunctionReturn(0); 8050 } 8051 8052 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8053 { 8054 PetscInt cellHeight, cStart, cEnd; 8055 8056 PetscFunctionBegin; 8057 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8058 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8059 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8060 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8061 PetscFunctionReturn(0); 8062 } 8063 8064 /*@ 8065 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8066 8067 Input Parameter: 8068 . dm - The DMPlex object 8069 8070 Output Parameter: 8071 . globalCellNumbers - Global cell numbers for all cells on this process 8072 8073 Level: developer 8074 8075 .seealso `DMPlexGetVertexNumbering()` 8076 @*/ 8077 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8078 { 8079 DM_Plex *mesh = (DM_Plex*) dm->data; 8080 8081 PetscFunctionBegin; 8082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8083 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8084 *globalCellNumbers = mesh->globalCellNumbers; 8085 PetscFunctionReturn(0); 8086 } 8087 8088 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8089 { 8090 PetscInt vStart, vEnd; 8091 8092 PetscFunctionBegin; 8093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8094 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8095 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8096 PetscFunctionReturn(0); 8097 } 8098 8099 /*@ 8100 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8101 8102 Input Parameter: 8103 . dm - The DMPlex object 8104 8105 Output Parameter: 8106 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8107 8108 Level: developer 8109 8110 .seealso `DMPlexGetCellNumbering()` 8111 @*/ 8112 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8113 { 8114 DM_Plex *mesh = (DM_Plex*) dm->data; 8115 8116 PetscFunctionBegin; 8117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8118 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8119 *globalVertexNumbers = mesh->globalVertexNumbers; 8120 PetscFunctionReturn(0); 8121 } 8122 8123 /*@ 8124 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8125 8126 Input Parameter: 8127 . dm - The DMPlex object 8128 8129 Output Parameter: 8130 . globalPointNumbers - Global numbers for all points on this process 8131 8132 Level: developer 8133 8134 .seealso `DMPlexGetCellNumbering()` 8135 @*/ 8136 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8137 { 8138 IS nums[4]; 8139 PetscInt depths[4], gdepths[4], starts[4]; 8140 PetscInt depth, d, shift = 0; 8141 8142 PetscFunctionBegin; 8143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8144 PetscCall(DMPlexGetDepth(dm, &depth)); 8145 /* For unstratified meshes use dim instead of depth */ 8146 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8147 for (d = 0; d <= depth; ++d) { 8148 PetscInt end; 8149 8150 depths[d] = depth-d; 8151 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8152 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8153 } 8154 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8155 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8156 for (d = 0; d <= depth; ++d) { 8157 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]); 8158 } 8159 for (d = 0; d <= depth; ++d) { 8160 PetscInt pStart, pEnd, gsize; 8161 8162 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8163 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8164 shift += gsize; 8165 } 8166 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8167 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8168 PetscFunctionReturn(0); 8169 } 8170 8171 /*@ 8172 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8173 8174 Input Parameter: 8175 . dm - The DMPlex object 8176 8177 Output Parameter: 8178 . ranks - The rank field 8179 8180 Options Database Keys: 8181 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8182 8183 Level: intermediate 8184 8185 .seealso: `DMView()` 8186 @*/ 8187 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8188 { 8189 DM rdm; 8190 PetscFE fe; 8191 PetscScalar *r; 8192 PetscMPIInt rank; 8193 DMPolytopeType ct; 8194 PetscInt dim, cStart, cEnd, c; 8195 PetscBool simplex; 8196 8197 PetscFunctionBeginUser; 8198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8199 PetscValidPointer(ranks, 2); 8200 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8201 PetscCall(DMClone(dm, &rdm)); 8202 PetscCall(DMGetDimension(rdm, &dim)); 8203 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8204 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8205 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8206 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8207 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8208 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8209 PetscCall(PetscFEDestroy(&fe)); 8210 PetscCall(DMCreateDS(rdm)); 8211 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8212 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8213 PetscCall(VecGetArray(*ranks, &r)); 8214 for (c = cStart; c < cEnd; ++c) { 8215 PetscScalar *lr; 8216 8217 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8218 if (lr) *lr = rank; 8219 } 8220 PetscCall(VecRestoreArray(*ranks, &r)); 8221 PetscCall(DMDestroy(&rdm)); 8222 PetscFunctionReturn(0); 8223 } 8224 8225 /*@ 8226 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8227 8228 Input Parameters: 8229 + dm - The DMPlex 8230 - label - The DMLabel 8231 8232 Output Parameter: 8233 . val - The label value field 8234 8235 Options Database Keys: 8236 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8237 8238 Level: intermediate 8239 8240 .seealso: `DMView()` 8241 @*/ 8242 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8243 { 8244 DM rdm; 8245 PetscFE fe; 8246 PetscScalar *v; 8247 PetscInt dim, cStart, cEnd, c; 8248 8249 PetscFunctionBeginUser; 8250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8251 PetscValidPointer(label, 2); 8252 PetscValidPointer(val, 3); 8253 PetscCall(DMClone(dm, &rdm)); 8254 PetscCall(DMGetDimension(rdm, &dim)); 8255 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8256 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8257 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8258 PetscCall(PetscFEDestroy(&fe)); 8259 PetscCall(DMCreateDS(rdm)); 8260 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8261 PetscCall(DMCreateGlobalVector(rdm, val)); 8262 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8263 PetscCall(VecGetArray(*val, &v)); 8264 for (c = cStart; c < cEnd; ++c) { 8265 PetscScalar *lv; 8266 PetscInt cval; 8267 8268 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8269 PetscCall(DMLabelGetValue(label, c, &cval)); 8270 *lv = cval; 8271 } 8272 PetscCall(VecRestoreArray(*val, &v)); 8273 PetscCall(DMDestroy(&rdm)); 8274 PetscFunctionReturn(0); 8275 } 8276 8277 /*@ 8278 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8279 8280 Input Parameter: 8281 . dm - The DMPlex object 8282 8283 Notes: 8284 This is a useful diagnostic when creating meshes programmatically. 8285 8286 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8287 8288 Level: developer 8289 8290 .seealso: `DMCreate()`, `DMSetFromOptions()` 8291 @*/ 8292 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8293 { 8294 PetscSection coneSection, supportSection; 8295 const PetscInt *cone, *support; 8296 PetscInt coneSize, c, supportSize, s; 8297 PetscInt pStart, pEnd, p, pp, csize, ssize; 8298 PetscBool storagecheck = PETSC_TRUE; 8299 8300 PetscFunctionBegin; 8301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8302 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8303 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8304 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8305 /* Check that point p is found in the support of its cone points, and vice versa */ 8306 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8307 for (p = pStart; p < pEnd; ++p) { 8308 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8309 PetscCall(DMPlexGetCone(dm, p, &cone)); 8310 for (c = 0; c < coneSize; ++c) { 8311 PetscBool dup = PETSC_FALSE; 8312 PetscInt d; 8313 for (d = c-1; d >= 0; --d) { 8314 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8315 } 8316 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8317 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8318 for (s = 0; s < supportSize; ++s) { 8319 if (support[s] == p) break; 8320 } 8321 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8322 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8323 for (s = 0; s < coneSize; ++s) { 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8325 } 8326 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8328 for (s = 0; s < supportSize; ++s) { 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8330 } 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8332 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]); 8333 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8334 } 8335 } 8336 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8337 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8338 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8339 PetscCall(DMPlexGetSupport(dm, p, &support)); 8340 for (s = 0; s < supportSize; ++s) { 8341 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8342 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8343 for (c = 0; c < coneSize; ++c) { 8344 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8345 if (cone[c] != pp) { c = 0; break; } 8346 if (cone[c] == p) break; 8347 } 8348 if (c >= coneSize) { 8349 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8350 for (c = 0; c < supportSize; ++c) { 8351 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8352 } 8353 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8354 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8355 for (c = 0; c < coneSize; ++c) { 8356 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8357 } 8358 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8359 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8360 } 8361 } 8362 } 8363 if (storagecheck) { 8364 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8365 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8366 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8367 } 8368 PetscFunctionReturn(0); 8369 } 8370 8371 /* 8372 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. 8373 */ 8374 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8375 { 8376 DMPolytopeType cct; 8377 PetscInt ptpoints[4]; 8378 const PetscInt *cone, *ccone, *ptcone; 8379 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8380 8381 PetscFunctionBegin; 8382 *unsplit = 0; 8383 switch (ct) { 8384 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8385 ptpoints[npt++] = c; 8386 break; 8387 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8388 PetscCall(DMPlexGetCone(dm, c, &cone)); 8389 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8390 for (cp = 0; cp < coneSize; ++cp) { 8391 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8392 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8393 } 8394 break; 8395 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8396 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8397 PetscCall(DMPlexGetCone(dm, c, &cone)); 8398 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8399 for (cp = 0; cp < coneSize; ++cp) { 8400 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8401 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8402 for (ccp = 0; ccp < cconeSize; ++ccp) { 8403 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8404 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8405 PetscInt p; 8406 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8407 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8408 } 8409 } 8410 } 8411 break; 8412 default: break; 8413 } 8414 for (pt = 0; pt < npt; ++pt) { 8415 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8416 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8417 } 8418 PetscFunctionReturn(0); 8419 } 8420 8421 /*@ 8422 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8423 8424 Input Parameters: 8425 + dm - The DMPlex object 8426 - cellHeight - Normally 0 8427 8428 Notes: 8429 This is a useful diagnostic when creating meshes programmatically. 8430 Currently applicable only to homogeneous simplex or tensor meshes. 8431 8432 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8433 8434 Level: developer 8435 8436 .seealso: `DMCreate()`, `DMSetFromOptions()` 8437 @*/ 8438 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8439 { 8440 DMPlexInterpolatedFlag interp; 8441 DMPolytopeType ct; 8442 PetscInt vStart, vEnd, cStart, cEnd, c; 8443 8444 PetscFunctionBegin; 8445 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8446 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8447 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8448 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8449 for (c = cStart; c < cEnd; ++c) { 8450 PetscInt *closure = NULL; 8451 PetscInt coneSize, closureSize, cl, Nv = 0; 8452 8453 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8454 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8455 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8456 if (interp == DMPLEX_INTERPOLATED_FULL) { 8457 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8458 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)); 8459 } 8460 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8461 for (cl = 0; cl < closureSize*2; cl += 2) { 8462 const PetscInt p = closure[cl]; 8463 if ((p >= vStart) && (p < vEnd)) ++Nv; 8464 } 8465 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8466 /* Special Case: Tensor faces with identified vertices */ 8467 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8468 PetscInt unsplit; 8469 8470 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8471 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8472 } 8473 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)); 8474 } 8475 PetscFunctionReturn(0); 8476 } 8477 8478 /*@ 8479 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8480 8481 Collective 8482 8483 Input Parameters: 8484 + dm - The DMPlex object 8485 - cellHeight - Normally 0 8486 8487 Notes: 8488 This is a useful diagnostic when creating meshes programmatically. 8489 This routine is only relevant for meshes that are fully interpolated across all ranks. 8490 It will error out if a partially interpolated mesh is given on some rank. 8491 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8492 8493 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8494 8495 Level: developer 8496 8497 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8498 @*/ 8499 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8500 { 8501 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8502 DMPlexInterpolatedFlag interpEnum; 8503 8504 PetscFunctionBegin; 8505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8506 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8507 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8508 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8509 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8510 PetscFunctionReturn(0); 8511 } 8512 8513 PetscCall(DMGetDimension(dm, &dim)); 8514 PetscCall(DMPlexGetDepth(dm, &depth)); 8515 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8516 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8517 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8518 for (c = cStart; c < cEnd; ++c) { 8519 const PetscInt *cone, *ornt, *faceSizes, *faces; 8520 const DMPolytopeType *faceTypes; 8521 DMPolytopeType ct; 8522 PetscInt numFaces, coneSize, f; 8523 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8524 8525 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8526 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8527 if (unsplit) continue; 8528 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8529 PetscCall(DMPlexGetCone(dm, c, &cone)); 8530 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8531 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8532 for (cl = 0; cl < closureSize*2; cl += 2) { 8533 const PetscInt p = closure[cl]; 8534 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8535 } 8536 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8537 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); 8538 for (f = 0; f < numFaces; ++f) { 8539 DMPolytopeType fct; 8540 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8541 8542 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8543 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8544 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8545 const PetscInt p = fclosure[cl]; 8546 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8547 } 8548 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]); 8549 for (v = 0; v < fnumCorners; ++v) { 8550 if (fclosure[v] != faces[fOff+v]) { 8551 PetscInt v1; 8552 8553 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8554 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8555 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8556 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8557 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8558 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]); 8559 } 8560 } 8561 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8562 fOff += faceSizes[f]; 8563 } 8564 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8565 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8566 } 8567 } 8568 PetscFunctionReturn(0); 8569 } 8570 8571 /*@ 8572 DMPlexCheckGeometry - Check the geometry of mesh cells 8573 8574 Input Parameter: 8575 . dm - The DMPlex object 8576 8577 Notes: 8578 This is a useful diagnostic when creating meshes programmatically. 8579 8580 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8581 8582 Level: developer 8583 8584 .seealso: `DMCreate()`, `DMSetFromOptions()` 8585 @*/ 8586 PetscErrorCode DMPlexCheckGeometry(DM dm) 8587 { 8588 Vec coordinates; 8589 PetscReal detJ, J[9], refVol = 1.0; 8590 PetscReal vol; 8591 PetscBool periodic; 8592 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8593 8594 PetscFunctionBegin; 8595 PetscCall(DMGetDimension(dm, &dim)); 8596 PetscCall(DMGetCoordinateDim(dm, &dE)); 8597 if (dim != dE) PetscFunctionReturn(0); 8598 PetscCall(DMPlexGetDepth(dm, &depth)); 8599 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 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 if (depth > 1 && !periodic) { 8631 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8632 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); 8633 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8634 } 8635 } 8636 PetscFunctionReturn(0); 8637 } 8638 8639 /*@ 8640 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8641 8642 Collective 8643 8644 Input Parameters: 8645 + dm - The DMPlex object 8646 - pointSF - The Point SF, or NULL for Point SF attached to DM 8647 8648 Notes: 8649 This is mainly intended for debugging/testing purposes. 8650 8651 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8652 8653 Level: developer 8654 8655 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8656 @*/ 8657 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8658 { 8659 PetscInt l, nleaves, nroots, overlap; 8660 const PetscInt *locals; 8661 const PetscSFNode *remotes; 8662 PetscBool distributed; 8663 MPI_Comm comm; 8664 PetscMPIInt rank; 8665 8666 PetscFunctionBegin; 8667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8668 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8669 else pointSF = dm->sf; 8670 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8671 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8672 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8673 { 8674 PetscMPIInt mpiFlag; 8675 8676 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8677 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8678 } 8679 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8680 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8681 if (!distributed) { 8682 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); 8683 PetscFunctionReturn(0); 8684 } 8685 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); 8686 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8687 8688 /* Check SF graph is compatible with DMPlex chart */ 8689 { 8690 PetscInt pStart, pEnd, maxLeaf; 8691 8692 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8693 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8694 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8695 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8696 } 8697 8698 /* Check Point SF has no local points referenced */ 8699 for (l = 0; l < nleaves; l++) { 8700 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); 8701 } 8702 8703 /* Check there are no cells in interface */ 8704 if (!overlap) { 8705 PetscInt cellHeight, cStart, cEnd; 8706 8707 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8708 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8709 for (l = 0; l < nleaves; ++l) { 8710 const PetscInt point = locals ? locals[l] : l; 8711 8712 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8713 } 8714 } 8715 8716 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8717 { 8718 const PetscInt *rootdegree; 8719 8720 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8721 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8722 for (l = 0; l < nleaves; ++l) { 8723 const PetscInt point = locals ? locals[l] : l; 8724 const PetscInt *cone; 8725 PetscInt coneSize, c, idx; 8726 8727 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8728 PetscCall(DMPlexGetCone(dm, point, &cone)); 8729 for (c = 0; c < coneSize; ++c) { 8730 if (!rootdegree[cone[c]]) { 8731 if (locals) { 8732 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8733 } else { 8734 idx = (cone[c] < nleaves) ? cone[c] : -1; 8735 } 8736 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8737 } 8738 } 8739 } 8740 } 8741 PetscFunctionReturn(0); 8742 } 8743 8744 /*@ 8745 DMPlexCheck - Perform various checks of Plex sanity 8746 8747 Input Parameter: 8748 . dm - The DMPlex object 8749 8750 Notes: 8751 This is a useful diagnostic when creating meshes programmatically. 8752 8753 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8754 8755 Currently does not include DMPlexCheckCellShape(). 8756 8757 Level: developer 8758 8759 .seealso: DMCreate(), DMSetFromOptions() 8760 @*/ 8761 PetscErrorCode DMPlexCheck(DM dm) 8762 { 8763 PetscInt cellHeight; 8764 8765 PetscFunctionBegin; 8766 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8767 PetscCall(DMPlexCheckSymmetry(dm)); 8768 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8769 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8770 PetscCall(DMPlexCheckGeometry(dm)); 8771 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8772 PetscCall(DMPlexCheckInterfaceCones(dm)); 8773 PetscFunctionReturn(0); 8774 } 8775 8776 typedef struct cell_stats 8777 { 8778 PetscReal min, max, sum, squaresum; 8779 PetscInt count; 8780 } cell_stats_t; 8781 8782 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8783 { 8784 PetscInt i, N = *len; 8785 8786 for (i = 0; i < N; i++) { 8787 cell_stats_t *A = (cell_stats_t *) a; 8788 cell_stats_t *B = (cell_stats_t *) b; 8789 8790 B->min = PetscMin(A->min,B->min); 8791 B->max = PetscMax(A->max,B->max); 8792 B->sum += A->sum; 8793 B->squaresum += A->squaresum; 8794 B->count += A->count; 8795 } 8796 } 8797 8798 /*@ 8799 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8800 8801 Collective on dm 8802 8803 Input Parameters: 8804 + dm - The DMPlex object 8805 . output - If true, statistics will be displayed on stdout 8806 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8807 8808 Notes: 8809 This is mainly intended for debugging/testing purposes. 8810 8811 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8812 8813 Level: developer 8814 8815 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8816 @*/ 8817 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8818 { 8819 DM dmCoarse; 8820 cell_stats_t stats, globalStats; 8821 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8822 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8823 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8824 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8825 PetscMPIInt rank,size; 8826 8827 PetscFunctionBegin; 8828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8829 stats.min = PETSC_MAX_REAL; 8830 stats.max = PETSC_MIN_REAL; 8831 stats.sum = stats.squaresum = 0.; 8832 stats.count = 0; 8833 8834 PetscCallMPI(MPI_Comm_size(comm, &size)); 8835 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8836 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8837 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8838 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8839 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8840 for (c = cStart; c < cEnd; c++) { 8841 PetscInt i; 8842 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8843 8844 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8845 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8846 for (i = 0; i < PetscSqr(cdim); ++i) { 8847 frobJ += J[i] * J[i]; 8848 frobInvJ += invJ[i] * invJ[i]; 8849 } 8850 cond2 = frobJ * frobInvJ; 8851 cond = PetscSqrtReal(cond2); 8852 8853 stats.min = PetscMin(stats.min,cond); 8854 stats.max = PetscMax(stats.max,cond); 8855 stats.sum += cond; 8856 stats.squaresum += cond2; 8857 stats.count++; 8858 if (output && cond > limit) { 8859 PetscSection coordSection; 8860 Vec coordsLocal; 8861 PetscScalar *coords = NULL; 8862 PetscInt Nv, d, clSize, cl, *closure = NULL; 8863 8864 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8865 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8866 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8867 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8868 for (i = 0; i < Nv/cdim; ++i) { 8869 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8870 for (d = 0; d < cdim; ++d) { 8871 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8872 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8873 } 8874 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8875 } 8876 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8877 for (cl = 0; cl < clSize*2; cl += 2) { 8878 const PetscInt edge = closure[cl]; 8879 8880 if ((edge >= eStart) && (edge < eEnd)) { 8881 PetscReal len; 8882 8883 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8884 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8885 } 8886 } 8887 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8888 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8889 } 8890 } 8891 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8892 8893 if (size > 1) { 8894 PetscMPIInt blockLengths[2] = {4,1}; 8895 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8896 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8897 MPI_Op statReduce; 8898 8899 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8900 PetscCallMPI(MPI_Type_commit(&statType)); 8901 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8902 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8903 PetscCallMPI(MPI_Op_free(&statReduce)); 8904 PetscCallMPI(MPI_Type_free(&statType)); 8905 } else { 8906 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8907 } 8908 if (rank == 0) { 8909 count = globalStats.count; 8910 min = globalStats.min; 8911 max = globalStats.max; 8912 mean = globalStats.sum / globalStats.count; 8913 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8914 } 8915 8916 if (output) { 8917 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)); 8918 } 8919 PetscCall(PetscFree2(J,invJ)); 8920 8921 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8922 if (dmCoarse) { 8923 PetscBool isplex; 8924 8925 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8926 if (isplex) { 8927 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8928 } 8929 } 8930 PetscFunctionReturn(0); 8931 } 8932 8933 /*@ 8934 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8935 orthogonal quality below given tolerance. 8936 8937 Collective on dm 8938 8939 Input Parameters: 8940 + dm - The DMPlex object 8941 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8942 - atol - [0, 1] Absolute tolerance for tagging cells. 8943 8944 Output Parameters: 8945 + OrthQual - Vec containing orthogonal quality per cell 8946 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8947 8948 Options Database Keys: 8949 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8950 supported. 8951 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8952 8953 Notes: 8954 Orthogonal quality is given by the following formula: 8955 8956 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8957 8958 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 8959 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8960 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8961 calculating the cosine of the angle between these vectors. 8962 8963 Orthogonal quality ranges from 1 (best) to 0 (worst). 8964 8965 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8966 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8967 8968 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8969 8970 Level: intermediate 8971 8972 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8973 @*/ 8974 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8975 { 8976 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8977 PetscInt *idx; 8978 PetscScalar *oqVals; 8979 const PetscScalar *cellGeomArr, *faceGeomArr; 8980 PetscReal *ci, *fi, *Ai; 8981 MPI_Comm comm; 8982 Vec cellgeom, facegeom; 8983 DM dmFace, dmCell; 8984 IS glob; 8985 ISLocalToGlobalMapping ltog; 8986 PetscViewer vwr; 8987 8988 PetscFunctionBegin; 8989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8990 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8991 PetscValidPointer(OrthQual, 4); 8992 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8993 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8994 PetscCall(DMGetDimension(dm, &nc)); 8995 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8996 { 8997 DMPlexInterpolatedFlag interpFlag; 8998 8999 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9000 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9001 PetscMPIInt rank; 9002 9003 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9004 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9005 } 9006 } 9007 if (OrthQualLabel) { 9008 PetscValidPointer(OrthQualLabel, 5); 9009 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9010 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9011 } else {*OrthQualLabel = NULL;} 9012 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9013 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9014 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9015 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9016 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9017 PetscCall(VecCreate(comm, OrthQual)); 9018 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9019 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9020 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9021 PetscCall(VecSetUp(*OrthQual)); 9022 PetscCall(ISDestroy(&glob)); 9023 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9024 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9025 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9026 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9027 PetscCall(VecGetDM(cellgeom, &dmCell)); 9028 PetscCall(VecGetDM(facegeom, &dmFace)); 9029 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9030 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9031 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9032 PetscInt cellarr[2], *adj = NULL; 9033 PetscScalar *cArr, *fArr; 9034 PetscReal minvalc = 1.0, minvalf = 1.0; 9035 PetscFVCellGeom *cg; 9036 9037 idx[cellIter] = cell-cStart; 9038 cellarr[0] = cell; 9039 /* Make indexing into cellGeom easier */ 9040 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9041 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9042 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9043 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9044 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9045 PetscInt i; 9046 const PetscInt neigh = adj[cellneigh]; 9047 PetscReal normci = 0, normfi = 0, normai = 0; 9048 PetscFVCellGeom *cgneigh; 9049 PetscFVFaceGeom *fg; 9050 9051 /* Don't count ourselves in the neighbor list */ 9052 if (neigh == cell) continue; 9053 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9054 cellarr[1] = neigh; 9055 { 9056 PetscInt numcovpts; 9057 const PetscInt *covpts; 9058 9059 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9060 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9061 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9062 } 9063 9064 /* Compute c_i, f_i and their norms */ 9065 for (i = 0; i < nc; i++) { 9066 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9067 fi[i] = fg->centroid[i] - cg->centroid[i]; 9068 Ai[i] = fg->normal[i]; 9069 normci += PetscPowReal(ci[i], 2); 9070 normfi += PetscPowReal(fi[i], 2); 9071 normai += PetscPowReal(Ai[i], 2); 9072 } 9073 normci = PetscSqrtReal(normci); 9074 normfi = PetscSqrtReal(normfi); 9075 normai = PetscSqrtReal(normai); 9076 9077 /* Normalize and compute for each face-cell-normal pair */ 9078 for (i = 0; i < nc; i++) { 9079 ci[i] = ci[i]/normci; 9080 fi[i] = fi[i]/normfi; 9081 Ai[i] = Ai[i]/normai; 9082 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9083 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9084 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9085 } 9086 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9087 minvalc = PetscRealPart(cArr[cellneighiter]); 9088 } 9089 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9090 minvalf = PetscRealPart(fArr[cellneighiter]); 9091 } 9092 } 9093 PetscCall(PetscFree(adj)); 9094 PetscCall(PetscFree2(cArr, fArr)); 9095 /* Defer to cell if they're equal */ 9096 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9097 if (OrthQualLabel) { 9098 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9099 } 9100 } 9101 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9102 PetscCall(VecAssemblyBegin(*OrthQual)); 9103 PetscCall(VecAssemblyEnd(*OrthQual)); 9104 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9105 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9106 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9107 if (OrthQualLabel) { 9108 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9109 } 9110 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9111 PetscCall(PetscViewerDestroy(&vwr)); 9112 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9113 PetscFunctionReturn(0); 9114 } 9115 9116 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9117 * interpolator construction */ 9118 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9119 { 9120 PetscSection section, newSection, gsection; 9121 PetscSF sf; 9122 PetscBool hasConstraints, ghasConstraints; 9123 9124 PetscFunctionBegin; 9125 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9126 PetscValidPointer(odm,2); 9127 PetscCall(DMGetLocalSection(dm, §ion)); 9128 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9129 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9130 if (!ghasConstraints) { 9131 PetscCall(PetscObjectReference((PetscObject)dm)); 9132 *odm = dm; 9133 PetscFunctionReturn(0); 9134 } 9135 PetscCall(DMClone(dm, odm)); 9136 PetscCall(DMCopyFields(dm, *odm)); 9137 PetscCall(DMGetLocalSection(*odm, &newSection)); 9138 PetscCall(DMGetPointSF(*odm, &sf)); 9139 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9140 PetscCall(DMSetGlobalSection(*odm, gsection)); 9141 PetscCall(PetscSectionDestroy(&gsection)); 9142 PetscFunctionReturn(0); 9143 } 9144 9145 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9146 { 9147 DM dmco, dmfo; 9148 Mat interpo; 9149 Vec rscale; 9150 Vec cglobalo, clocal; 9151 Vec fglobal, fglobalo, flocal; 9152 PetscBool regular; 9153 9154 PetscFunctionBegin; 9155 PetscCall(DMGetFullDM(dmc, &dmco)); 9156 PetscCall(DMGetFullDM(dmf, &dmfo)); 9157 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9158 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9159 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9160 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9161 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9162 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9163 PetscCall(VecSet(cglobalo, 0.)); 9164 PetscCall(VecSet(clocal, 0.)); 9165 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9166 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9167 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9168 PetscCall(VecSet(fglobal, 0.)); 9169 PetscCall(VecSet(fglobalo, 0.)); 9170 PetscCall(VecSet(flocal, 0.)); 9171 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9172 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9173 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9174 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9175 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9176 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9177 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9178 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9179 *shift = fglobal; 9180 PetscCall(VecDestroy(&flocal)); 9181 PetscCall(VecDestroy(&fglobalo)); 9182 PetscCall(VecDestroy(&clocal)); 9183 PetscCall(VecDestroy(&cglobalo)); 9184 PetscCall(VecDestroy(&rscale)); 9185 PetscCall(MatDestroy(&interpo)); 9186 PetscCall(DMDestroy(&dmfo)); 9187 PetscCall(DMDestroy(&dmco)); 9188 PetscFunctionReturn(0); 9189 } 9190 9191 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9192 { 9193 PetscObject shifto; 9194 Vec shift; 9195 9196 PetscFunctionBegin; 9197 if (!interp) { 9198 Vec rscale; 9199 9200 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9201 PetscCall(VecDestroy(&rscale)); 9202 } else { 9203 PetscCall(PetscObjectReference((PetscObject)interp)); 9204 } 9205 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9206 if (!shifto) { 9207 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9208 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9209 shifto = (PetscObject) shift; 9210 PetscCall(VecDestroy(&shift)); 9211 } 9212 shift = (Vec) shifto; 9213 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9214 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9215 PetscCall(MatDestroy(&interp)); 9216 PetscFunctionReturn(0); 9217 } 9218 9219 /* Pointwise interpolation 9220 Just code FEM for now 9221 u^f = I u^c 9222 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9223 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9224 I_{ij} = psi^f_i phi^c_j 9225 */ 9226 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9227 { 9228 PetscSection gsc, gsf; 9229 PetscInt m, n; 9230 void *ctx; 9231 DM cdm; 9232 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9233 9234 PetscFunctionBegin; 9235 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9236 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9237 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9238 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9239 9240 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9241 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9242 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9243 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9244 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9245 9246 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9247 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9248 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9249 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9250 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9251 if (scaling) { 9252 /* Use naive scaling */ 9253 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9254 } 9255 PetscFunctionReturn(0); 9256 } 9257 9258 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9259 { 9260 VecScatter ctx; 9261 9262 PetscFunctionBegin; 9263 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9264 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9265 PetscCall(VecScatterDestroy(&ctx)); 9266 PetscFunctionReturn(0); 9267 } 9268 9269 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9270 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9271 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9272 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9273 { 9274 const PetscInt Nc = uOff[1] - uOff[0]; 9275 PetscInt c; 9276 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9277 } 9278 9279 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9280 { 9281 DM dmc; 9282 PetscDS ds; 9283 Vec ones, locmass; 9284 IS cellIS; 9285 PetscFormKey key; 9286 PetscInt depth; 9287 9288 PetscFunctionBegin; 9289 PetscCall(DMClone(dm, &dmc)); 9290 PetscCall(DMCopyDisc(dm, dmc)); 9291 PetscCall(DMGetDS(dmc, &ds)); 9292 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9293 PetscCall(DMCreateGlobalVector(dmc, mass)); 9294 PetscCall(DMGetLocalVector(dmc, &ones)); 9295 PetscCall(DMGetLocalVector(dmc, &locmass)); 9296 PetscCall(DMPlexGetDepth(dmc, &depth)); 9297 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9298 PetscCall(VecSet(locmass, 0.0)); 9299 PetscCall(VecSet(ones, 1.0)); 9300 key.label = NULL; 9301 key.value = 0; 9302 key.field = 0; 9303 key.part = 0; 9304 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9305 PetscCall(ISDestroy(&cellIS)); 9306 PetscCall(VecSet(*mass, 0.0)); 9307 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9308 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9309 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9310 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9311 PetscCall(DMDestroy(&dmc)); 9312 PetscFunctionReturn(0); 9313 } 9314 9315 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9316 { 9317 PetscSection gsc, gsf; 9318 PetscInt m, n; 9319 void *ctx; 9320 DM cdm; 9321 PetscBool regular; 9322 9323 PetscFunctionBegin; 9324 if (dmFine == dmCoarse) { 9325 DM dmc; 9326 PetscDS ds; 9327 PetscWeakForm wf; 9328 Vec u; 9329 IS cellIS; 9330 PetscFormKey key; 9331 PetscInt depth; 9332 9333 PetscCall(DMClone(dmFine, &dmc)); 9334 PetscCall(DMCopyDisc(dmFine, dmc)); 9335 PetscCall(DMGetDS(dmc, &ds)); 9336 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9337 PetscCall(PetscWeakFormClear(wf)); 9338 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9339 PetscCall(DMCreateMatrix(dmc, mass)); 9340 PetscCall(DMGetGlobalVector(dmc, &u)); 9341 PetscCall(DMPlexGetDepth(dmc, &depth)); 9342 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9343 PetscCall(MatZeroEntries(*mass)); 9344 key.label = NULL; 9345 key.value = 0; 9346 key.field = 0; 9347 key.part = 0; 9348 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9349 PetscCall(ISDestroy(&cellIS)); 9350 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9351 PetscCall(DMDestroy(&dmc)); 9352 } else { 9353 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9354 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9355 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9356 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9357 9358 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9359 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9360 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9361 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9362 9363 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9364 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9365 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9366 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9367 } 9368 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9369 PetscFunctionReturn(0); 9370 } 9371 9372 /*@ 9373 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9374 9375 Input Parameter: 9376 . dm - The DMPlex object 9377 9378 Output Parameter: 9379 . regular - The flag 9380 9381 Level: intermediate 9382 9383 .seealso: `DMPlexSetRegularRefinement()` 9384 @*/ 9385 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9386 { 9387 PetscFunctionBegin; 9388 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9389 PetscValidBoolPointer(regular, 2); 9390 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9391 PetscFunctionReturn(0); 9392 } 9393 9394 /*@ 9395 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9396 9397 Input Parameters: 9398 + dm - The DMPlex object 9399 - regular - The flag 9400 9401 Level: intermediate 9402 9403 .seealso: `DMPlexGetRegularRefinement()` 9404 @*/ 9405 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9406 { 9407 PetscFunctionBegin; 9408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9409 ((DM_Plex *) dm->data)->regularRefinement = regular; 9410 PetscFunctionReturn(0); 9411 } 9412 9413 /* anchors */ 9414 /*@ 9415 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9416 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9417 9418 not collective 9419 9420 Input Parameter: 9421 . dm - The DMPlex object 9422 9423 Output Parameters: 9424 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9425 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9426 9427 Level: intermediate 9428 9429 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9430 @*/ 9431 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9432 { 9433 DM_Plex *plex = (DM_Plex *)dm->data; 9434 9435 PetscFunctionBegin; 9436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9437 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9438 if (anchorSection) *anchorSection = plex->anchorSection; 9439 if (anchorIS) *anchorIS = plex->anchorIS; 9440 PetscFunctionReturn(0); 9441 } 9442 9443 /*@ 9444 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9445 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9446 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9447 9448 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9449 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9450 9451 collective on dm 9452 9453 Input Parameters: 9454 + dm - The DMPlex object 9455 . 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). 9456 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9457 9458 The reference counts of anchorSection and anchorIS are incremented. 9459 9460 Level: intermediate 9461 9462 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9463 @*/ 9464 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9465 { 9466 DM_Plex *plex = (DM_Plex *)dm->data; 9467 PetscMPIInt result; 9468 9469 PetscFunctionBegin; 9470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9471 if (anchorSection) { 9472 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9473 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9474 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9475 } 9476 if (anchorIS) { 9477 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9478 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9479 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9480 } 9481 9482 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9483 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9484 plex->anchorSection = anchorSection; 9485 9486 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9487 PetscCall(ISDestroy(&plex->anchorIS)); 9488 plex->anchorIS = anchorIS; 9489 9490 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9491 PetscInt size, a, pStart, pEnd; 9492 const PetscInt *anchors; 9493 9494 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9495 PetscCall(ISGetLocalSize(anchorIS,&size)); 9496 PetscCall(ISGetIndices(anchorIS,&anchors)); 9497 for (a = 0; a < size; a++) { 9498 PetscInt p; 9499 9500 p = anchors[a]; 9501 if (p >= pStart && p < pEnd) { 9502 PetscInt dof; 9503 9504 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9505 if (dof) { 9506 9507 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9508 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9509 } 9510 } 9511 } 9512 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9513 } 9514 /* reset the generic constraints */ 9515 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9516 PetscFunctionReturn(0); 9517 } 9518 9519 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9520 { 9521 PetscSection anchorSection; 9522 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9523 9524 PetscFunctionBegin; 9525 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9526 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9527 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9528 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9529 if (numFields) { 9530 PetscInt f; 9531 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9532 9533 for (f = 0; f < numFields; f++) { 9534 PetscInt numComp; 9535 9536 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9537 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9538 } 9539 } 9540 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9541 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9542 pStart = PetscMax(pStart,sStart); 9543 pEnd = PetscMin(pEnd,sEnd); 9544 pEnd = PetscMax(pStart,pEnd); 9545 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9546 for (p = pStart; p < pEnd; p++) { 9547 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9548 if (dof) { 9549 PetscCall(PetscSectionGetDof(section,p,&dof)); 9550 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9551 for (f = 0; f < numFields; f++) { 9552 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9553 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9554 } 9555 } 9556 } 9557 PetscCall(PetscSectionSetUp(*cSec)); 9558 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9559 PetscFunctionReturn(0); 9560 } 9561 9562 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9563 { 9564 PetscSection aSec; 9565 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9566 const PetscInt *anchors; 9567 PetscInt numFields, f; 9568 IS aIS; 9569 MatType mtype; 9570 PetscBool iscuda,iskokkos; 9571 9572 PetscFunctionBegin; 9573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9574 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9575 PetscCall(PetscSectionGetStorageSize(section, &n)); 9576 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9577 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9578 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9579 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9580 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9581 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9582 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9583 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9584 else mtype = MATSEQAIJ; 9585 PetscCall(MatSetType(*cMat,mtype)); 9586 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9587 PetscCall(ISGetIndices(aIS,&anchors)); 9588 /* cSec will be a subset of aSec and section */ 9589 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9590 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9591 PetscCall(PetscMalloc1(m+1,&i)); 9592 i[0] = 0; 9593 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9594 for (p = pStart; p < pEnd; p++) { 9595 PetscInt rDof, rOff, r; 9596 9597 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9598 if (!rDof) continue; 9599 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9600 if (numFields) { 9601 for (f = 0; f < numFields; f++) { 9602 annz = 0; 9603 for (r = 0; r < rDof; r++) { 9604 a = anchors[rOff + r]; 9605 if (a < sStart || a >= sEnd) continue; 9606 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9607 annz += aDof; 9608 } 9609 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9610 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9611 for (q = 0; q < dof; q++) { 9612 i[off + q + 1] = i[off + q] + annz; 9613 } 9614 } 9615 } else { 9616 annz = 0; 9617 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9618 for (q = 0; q < dof; q++) { 9619 a = anchors[rOff + q]; 9620 if (a < sStart || a >= sEnd) continue; 9621 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9622 annz += aDof; 9623 } 9624 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9625 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9626 for (q = 0; q < dof; q++) { 9627 i[off + q + 1] = i[off + q] + annz; 9628 } 9629 } 9630 } 9631 nnz = i[m]; 9632 PetscCall(PetscMalloc1(nnz,&j)); 9633 offset = 0; 9634 for (p = pStart; p < pEnd; p++) { 9635 if (numFields) { 9636 for (f = 0; f < numFields; f++) { 9637 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9638 for (q = 0; q < dof; q++) { 9639 PetscInt rDof, rOff, r; 9640 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9641 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9642 for (r = 0; r < rDof; r++) { 9643 PetscInt s; 9644 9645 a = anchors[rOff + r]; 9646 if (a < sStart || a >= sEnd) continue; 9647 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9648 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9649 for (s = 0; s < aDof; s++) { 9650 j[offset++] = aOff + s; 9651 } 9652 } 9653 } 9654 } 9655 } else { 9656 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9657 for (q = 0; q < dof; q++) { 9658 PetscInt rDof, rOff, r; 9659 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9660 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9661 for (r = 0; r < rDof; r++) { 9662 PetscInt s; 9663 9664 a = anchors[rOff + r]; 9665 if (a < sStart || a >= sEnd) continue; 9666 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9667 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9668 for (s = 0; s < aDof; s++) { 9669 j[offset++] = aOff + s; 9670 } 9671 } 9672 } 9673 } 9674 } 9675 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9676 PetscCall(PetscFree(i)); 9677 PetscCall(PetscFree(j)); 9678 PetscCall(ISRestoreIndices(aIS,&anchors)); 9679 PetscFunctionReturn(0); 9680 } 9681 9682 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9683 { 9684 DM_Plex *plex = (DM_Plex *)dm->data; 9685 PetscSection anchorSection, section, cSec; 9686 Mat cMat; 9687 9688 PetscFunctionBegin; 9689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9690 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9691 if (anchorSection) { 9692 PetscInt Nf; 9693 9694 PetscCall(DMGetLocalSection(dm,§ion)); 9695 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9696 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9697 PetscCall(DMGetNumFields(dm,&Nf)); 9698 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9699 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9700 PetscCall(PetscSectionDestroy(&cSec)); 9701 PetscCall(MatDestroy(&cMat)); 9702 } 9703 PetscFunctionReturn(0); 9704 } 9705 9706 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9707 { 9708 IS subis; 9709 PetscSection section, subsection; 9710 9711 PetscFunctionBegin; 9712 PetscCall(DMGetLocalSection(dm, §ion)); 9713 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9714 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9715 /* Create subdomain */ 9716 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9717 /* Create submodel */ 9718 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9719 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9720 PetscCall(DMSetLocalSection(*subdm, subsection)); 9721 PetscCall(PetscSectionDestroy(&subsection)); 9722 PetscCall(DMCopyDisc(dm, *subdm)); 9723 /* Create map from submodel to global model */ 9724 if (is) { 9725 PetscSection sectionGlobal, subsectionGlobal; 9726 IS spIS; 9727 const PetscInt *spmap; 9728 PetscInt *subIndices; 9729 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9730 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9731 9732 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9733 PetscCall(ISGetIndices(spIS, &spmap)); 9734 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9735 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9736 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9737 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9738 for (p = pStart; p < pEnd; ++p) { 9739 PetscInt gdof, pSubSize = 0; 9740 9741 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9742 if (gdof > 0) { 9743 for (f = 0; f < Nf; ++f) { 9744 PetscInt fdof, fcdof; 9745 9746 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9747 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9748 pSubSize += fdof-fcdof; 9749 } 9750 subSize += pSubSize; 9751 if (pSubSize) { 9752 if (bs < 0) { 9753 bs = pSubSize; 9754 } else if (bs != pSubSize) { 9755 /* Layout does not admit a pointwise block size */ 9756 bs = 1; 9757 } 9758 } 9759 } 9760 } 9761 /* Must have same blocksize on all procs (some might have no points) */ 9762 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9763 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9764 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9765 else {bs = bsMinMax[0];} 9766 PetscCall(PetscMalloc1(subSize, &subIndices)); 9767 for (p = pStart; p < pEnd; ++p) { 9768 PetscInt gdof, goff; 9769 9770 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9771 if (gdof > 0) { 9772 const PetscInt point = spmap[p]; 9773 9774 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9775 for (f = 0; f < Nf; ++f) { 9776 PetscInt fdof, fcdof, fc, f2, poff = 0; 9777 9778 /* Can get rid of this loop by storing field information in the global section */ 9779 for (f2 = 0; f2 < f; ++f2) { 9780 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9781 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9782 poff += fdof-fcdof; 9783 } 9784 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9785 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9786 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9787 subIndices[subOff] = goff+poff+fc; 9788 } 9789 } 9790 } 9791 } 9792 PetscCall(ISRestoreIndices(spIS, &spmap)); 9793 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9794 if (bs > 1) { 9795 /* We need to check that the block size does not come from non-contiguous fields */ 9796 PetscInt i, j, set = 1; 9797 for (i = 0; i < subSize; i += bs) { 9798 for (j = 0; j < bs; ++j) { 9799 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9800 } 9801 } 9802 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9803 } 9804 /* Attach nullspace */ 9805 for (f = 0; f < Nf; ++f) { 9806 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9807 if ((*subdm)->nullspaceConstructors[f]) break; 9808 } 9809 if (f < Nf) { 9810 MatNullSpace nullSpace; 9811 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9812 9813 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9814 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9815 } 9816 } 9817 PetscFunctionReturn(0); 9818 } 9819 9820 /*@ 9821 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9822 9823 Input Parameter: 9824 - dm - The DM 9825 9826 Level: developer 9827 9828 Options Database Keys: 9829 . -dm_plex_monitor_throughput - Activate the monitor 9830 9831 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9832 @*/ 9833 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9834 { 9835 #if defined(PETSC_USE_LOG) 9836 PetscStageLog stageLog; 9837 PetscLogEvent event; 9838 PetscLogStage stage; 9839 PetscEventPerfInfo eventInfo; 9840 PetscReal cellRate, flopRate; 9841 PetscInt cStart, cEnd, Nf, N; 9842 const char *name; 9843 #endif 9844 9845 PetscFunctionBegin; 9846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9847 #if defined(PETSC_USE_LOG) 9848 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9849 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9850 PetscCall(DMGetNumFields(dm, &Nf)); 9851 PetscCall(PetscLogGetStageLog(&stageLog)); 9852 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9853 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9854 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9855 N = (cEnd - cStart)*Nf*eventInfo.count; 9856 flopRate = eventInfo.flops/eventInfo.time; 9857 cellRate = N/eventInfo.time; 9858 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))); 9859 #else 9860 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9861 #endif 9862 PetscFunctionReturn(0); 9863 } 9864