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