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