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 PetscCheck(numVals % Nc == 0,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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCall(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 PetscCall(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 PetscCall(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 PetscCheck(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 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1666 PetscCall(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(!(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 PetscCheck(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 PetscCheck(!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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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) {PetscCheck(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 PetscCheck(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 PetscCheck(*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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 PetscCheck(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 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7529 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7530 if (ierr) { 7531 PetscMPIInt rank; 7532 7533 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7534 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7535 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7536 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7537 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7538 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7539 } 7540 if (mesh->printFEM > 1) { 7541 PetscInt i; 7542 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7543 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", indices[i])); 7544 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7545 } 7546 7547 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7548 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7549 PetscFunctionReturn(0); 7550 } 7551 7552 /*@C 7553 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7554 7555 Not collective 7556 7557 Input Parameters: 7558 + dmRow - The DM for the row fields 7559 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7560 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7561 . dmCol - The DM for the column fields 7562 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7563 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7564 . A - The matrix 7565 . point - The point in the DMs 7566 . values - The array of values 7567 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7568 7569 Level: intermediate 7570 7571 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7572 @*/ 7573 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7574 { 7575 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7576 PetscInt *indicesRow, *indicesCol; 7577 PetscInt numIndicesRow, numIndicesCol; 7578 const PetscScalar *valuesOrig = values; 7579 PetscErrorCode ierr; 7580 7581 PetscFunctionBegin; 7582 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7583 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7584 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7585 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7586 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7587 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7588 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7589 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7590 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7591 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7592 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7593 7594 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7595 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7596 7597 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7598 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7599 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7600 if (ierr) { 7601 PetscMPIInt rank; 7602 7603 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7604 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7605 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7606 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7607 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7608 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7609 } 7610 7611 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7612 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7613 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7614 PetscFunctionReturn(0); 7615 } 7616 7617 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7618 { 7619 DM_Plex *mesh = (DM_Plex*) dmf->data; 7620 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7621 PetscInt *cpoints = NULL; 7622 PetscInt *findices, *cindices; 7623 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7624 PetscInt foffsets[32], coffsets[32]; 7625 DMPolytopeType ct; 7626 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7627 PetscErrorCode ierr; 7628 7629 PetscFunctionBegin; 7630 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7631 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7632 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7633 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7634 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7635 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7636 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7637 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7638 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7639 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7640 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7641 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7642 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7643 PetscCall(PetscArrayzero(foffsets, 32)); 7644 PetscCall(PetscArrayzero(coffsets, 32)); 7645 /* Column indices */ 7646 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7647 maxFPoints = numCPoints; 7648 /* Compress out points not in the section */ 7649 /* TODO: Squeeze out points with 0 dof as well */ 7650 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7651 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7652 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7653 cpoints[q*2] = cpoints[p]; 7654 cpoints[q*2+1] = cpoints[p+1]; 7655 ++q; 7656 } 7657 } 7658 numCPoints = q; 7659 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7660 PetscInt fdof; 7661 7662 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7663 if (!dof) continue; 7664 for (f = 0; f < numFields; ++f) { 7665 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7666 coffsets[f+1] += fdof; 7667 } 7668 numCIndices += dof; 7669 } 7670 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7671 /* Row indices */ 7672 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7673 { 7674 DMPlexTransform tr; 7675 DMPolytopeType *rct; 7676 PetscInt *rsize, *rcone, *rornt, Nt; 7677 7678 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7679 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7680 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7681 numSubcells = rsize[Nt-1]; 7682 PetscCall(DMPlexTransformDestroy(&tr)); 7683 } 7684 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7685 for (r = 0, q = 0; r < numSubcells; ++r) { 7686 /* TODO Map from coarse to fine cells */ 7687 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7688 /* Compress out points not in the section */ 7689 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7690 for (p = 0; p < numFPoints*2; p += 2) { 7691 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7692 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7693 if (!dof) continue; 7694 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7695 if (s < q) continue; 7696 ftotpoints[q*2] = fpoints[p]; 7697 ftotpoints[q*2+1] = fpoints[p+1]; 7698 ++q; 7699 } 7700 } 7701 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7702 } 7703 numFPoints = q; 7704 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7705 PetscInt fdof; 7706 7707 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7708 if (!dof) continue; 7709 for (f = 0; f < numFields; ++f) { 7710 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7711 foffsets[f+1] += fdof; 7712 } 7713 numFIndices += dof; 7714 } 7715 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7716 7717 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7718 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7719 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7720 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7721 if (numFields) { 7722 const PetscInt **permsF[32] = {NULL}; 7723 const PetscInt **permsC[32] = {NULL}; 7724 7725 for (f = 0; f < numFields; f++) { 7726 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7727 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7728 } 7729 for (p = 0; p < numFPoints; p++) { 7730 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7731 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7732 } 7733 for (p = 0; p < numCPoints; p++) { 7734 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7735 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7736 } 7737 for (f = 0; f < numFields; f++) { 7738 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7739 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7740 } 7741 } else { 7742 const PetscInt **permsF = NULL; 7743 const PetscInt **permsC = NULL; 7744 7745 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7746 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7747 for (p = 0, off = 0; p < numFPoints; p++) { 7748 const PetscInt *perm = permsF ? permsF[p] : NULL; 7749 7750 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7751 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7752 } 7753 for (p = 0, off = 0; p < numCPoints; p++) { 7754 const PetscInt *perm = permsC ? permsC[p] : NULL; 7755 7756 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7757 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7758 } 7759 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7760 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7761 } 7762 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7763 /* TODO: flips */ 7764 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7765 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7766 if (ierr) { 7767 PetscMPIInt rank; 7768 7769 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7770 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7771 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7772 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7773 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7774 } 7775 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7776 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7777 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7778 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7779 PetscFunctionReturn(0); 7780 } 7781 7782 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7783 { 7784 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7785 PetscInt *cpoints = NULL; 7786 PetscInt foffsets[32], coffsets[32]; 7787 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7788 DMPolytopeType ct; 7789 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7790 7791 PetscFunctionBegin; 7792 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7793 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7794 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7795 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7796 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7797 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7798 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7799 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7800 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7801 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7802 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7803 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7804 PetscCall(PetscArrayzero(foffsets, 32)); 7805 PetscCall(PetscArrayzero(coffsets, 32)); 7806 /* Column indices */ 7807 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7808 maxFPoints = numCPoints; 7809 /* Compress out points not in the section */ 7810 /* TODO: Squeeze out points with 0 dof as well */ 7811 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7812 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7813 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7814 cpoints[q*2] = cpoints[p]; 7815 cpoints[q*2+1] = cpoints[p+1]; 7816 ++q; 7817 } 7818 } 7819 numCPoints = q; 7820 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7821 PetscInt fdof; 7822 7823 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7824 if (!dof) continue; 7825 for (f = 0; f < numFields; ++f) { 7826 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7827 coffsets[f+1] += fdof; 7828 } 7829 numCIndices += dof; 7830 } 7831 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7832 /* Row indices */ 7833 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7834 { 7835 DMPlexTransform tr; 7836 DMPolytopeType *rct; 7837 PetscInt *rsize, *rcone, *rornt, Nt; 7838 7839 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7840 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7841 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7842 numSubcells = rsize[Nt-1]; 7843 PetscCall(DMPlexTransformDestroy(&tr)); 7844 } 7845 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7846 for (r = 0, q = 0; r < numSubcells; ++r) { 7847 /* TODO Map from coarse to fine cells */ 7848 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7849 /* Compress out points not in the section */ 7850 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7851 for (p = 0; p < numFPoints*2; p += 2) { 7852 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7853 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7854 if (!dof) continue; 7855 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7856 if (s < q) continue; 7857 ftotpoints[q*2] = fpoints[p]; 7858 ftotpoints[q*2+1] = fpoints[p+1]; 7859 ++q; 7860 } 7861 } 7862 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7863 } 7864 numFPoints = q; 7865 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7866 PetscInt fdof; 7867 7868 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7869 if (!dof) continue; 7870 for (f = 0; f < numFields; ++f) { 7871 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7872 foffsets[f+1] += fdof; 7873 } 7874 numFIndices += dof; 7875 } 7876 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7877 7878 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7879 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7880 if (numFields) { 7881 const PetscInt **permsF[32] = {NULL}; 7882 const PetscInt **permsC[32] = {NULL}; 7883 7884 for (f = 0; f < numFields; f++) { 7885 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7886 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7887 } 7888 for (p = 0; p < numFPoints; p++) { 7889 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7890 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7891 } 7892 for (p = 0; p < numCPoints; p++) { 7893 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7894 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7895 } 7896 for (f = 0; f < numFields; f++) { 7897 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7898 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7899 } 7900 } else { 7901 const PetscInt **permsF = NULL; 7902 const PetscInt **permsC = NULL; 7903 7904 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7905 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7906 for (p = 0, off = 0; p < numFPoints; p++) { 7907 const PetscInt *perm = permsF ? permsF[p] : NULL; 7908 7909 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7910 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7911 } 7912 for (p = 0, off = 0; p < numCPoints; p++) { 7913 const PetscInt *perm = permsC ? permsC[p] : NULL; 7914 7915 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7916 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7917 } 7918 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7919 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7920 } 7921 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7922 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7923 PetscFunctionReturn(0); 7924 } 7925 7926 /*@C 7927 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7928 7929 Input Parameter: 7930 . dm - The DMPlex object 7931 7932 Output Parameter: 7933 . cellHeight - The height of a cell 7934 7935 Level: developer 7936 7937 .seealso DMPlexSetVTKCellHeight() 7938 @*/ 7939 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7940 { 7941 DM_Plex *mesh = (DM_Plex*) dm->data; 7942 7943 PetscFunctionBegin; 7944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7945 PetscValidIntPointer(cellHeight, 2); 7946 *cellHeight = mesh->vtkCellHeight; 7947 PetscFunctionReturn(0); 7948 } 7949 7950 /*@C 7951 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7952 7953 Input Parameters: 7954 + dm - The DMPlex object 7955 - cellHeight - The height of a cell 7956 7957 Level: developer 7958 7959 .seealso DMPlexGetVTKCellHeight() 7960 @*/ 7961 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7962 { 7963 DM_Plex *mesh = (DM_Plex*) dm->data; 7964 7965 PetscFunctionBegin; 7966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7967 mesh->vtkCellHeight = cellHeight; 7968 PetscFunctionReturn(0); 7969 } 7970 7971 /*@ 7972 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7973 7974 Input Parameter: 7975 . dm - The DMPlex object 7976 7977 Output Parameters: 7978 + gcStart - The first ghost cell, or NULL 7979 - gcEnd - The upper bound on ghost cells, or NULL 7980 7981 Level: advanced 7982 7983 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 7984 @*/ 7985 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7986 { 7987 DMLabel ctLabel; 7988 7989 PetscFunctionBegin; 7990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7991 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7992 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7993 PetscFunctionReturn(0); 7994 } 7995 7996 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 7997 { 7998 PetscSection section, globalSection; 7999 PetscInt *numbers, p; 8000 8001 PetscFunctionBegin; 8002 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8003 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8004 for (p = pStart; p < pEnd; ++p) { 8005 PetscCall(PetscSectionSetDof(section, p, 1)); 8006 } 8007 PetscCall(PetscSectionSetUp(section)); 8008 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8009 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8010 for (p = pStart; p < pEnd; ++p) { 8011 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8012 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8013 else numbers[p-pStart] += shift; 8014 } 8015 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8016 if (globalSize) { 8017 PetscLayout layout; 8018 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8019 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8020 PetscCall(PetscLayoutDestroy(&layout)); 8021 } 8022 PetscCall(PetscSectionDestroy(§ion)); 8023 PetscCall(PetscSectionDestroy(&globalSection)); 8024 PetscFunctionReturn(0); 8025 } 8026 8027 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8028 { 8029 PetscInt cellHeight, cStart, cEnd; 8030 8031 PetscFunctionBegin; 8032 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8033 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8034 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8035 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8036 PetscFunctionReturn(0); 8037 } 8038 8039 /*@ 8040 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8041 8042 Input Parameter: 8043 . dm - The DMPlex object 8044 8045 Output Parameter: 8046 . globalCellNumbers - Global cell numbers for all cells on this process 8047 8048 Level: developer 8049 8050 .seealso DMPlexGetVertexNumbering() 8051 @*/ 8052 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8053 { 8054 DM_Plex *mesh = (DM_Plex*) dm->data; 8055 8056 PetscFunctionBegin; 8057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8058 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8059 *globalCellNumbers = mesh->globalCellNumbers; 8060 PetscFunctionReturn(0); 8061 } 8062 8063 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8064 { 8065 PetscInt vStart, vEnd; 8066 8067 PetscFunctionBegin; 8068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8069 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8070 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8071 PetscFunctionReturn(0); 8072 } 8073 8074 /*@ 8075 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8076 8077 Input Parameter: 8078 . dm - The DMPlex object 8079 8080 Output Parameter: 8081 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8082 8083 Level: developer 8084 8085 .seealso DMPlexGetCellNumbering() 8086 @*/ 8087 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8088 { 8089 DM_Plex *mesh = (DM_Plex*) dm->data; 8090 8091 PetscFunctionBegin; 8092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8093 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8094 *globalVertexNumbers = mesh->globalVertexNumbers; 8095 PetscFunctionReturn(0); 8096 } 8097 8098 /*@ 8099 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8100 8101 Input Parameter: 8102 . dm - The DMPlex object 8103 8104 Output Parameter: 8105 . globalPointNumbers - Global numbers for all points on this process 8106 8107 Level: developer 8108 8109 .seealso DMPlexGetCellNumbering() 8110 @*/ 8111 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8112 { 8113 IS nums[4]; 8114 PetscInt depths[4], gdepths[4], starts[4]; 8115 PetscInt depth, d, shift = 0; 8116 8117 PetscFunctionBegin; 8118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8119 PetscCall(DMPlexGetDepth(dm, &depth)); 8120 /* For unstratified meshes use dim instead of depth */ 8121 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8122 for (d = 0; d <= depth; ++d) { 8123 PetscInt end; 8124 8125 depths[d] = depth-d; 8126 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8127 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8128 } 8129 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8130 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8131 for (d = 0; d <= depth; ++d) { 8132 PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]); 8133 } 8134 for (d = 0; d <= depth; ++d) { 8135 PetscInt pStart, pEnd, gsize; 8136 8137 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8138 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8139 shift += gsize; 8140 } 8141 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8142 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8143 PetscFunctionReturn(0); 8144 } 8145 8146 /*@ 8147 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8148 8149 Input Parameter: 8150 . dm - The DMPlex object 8151 8152 Output Parameter: 8153 . ranks - The rank field 8154 8155 Options Database Keys: 8156 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8157 8158 Level: intermediate 8159 8160 .seealso: DMView() 8161 @*/ 8162 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8163 { 8164 DM rdm; 8165 PetscFE fe; 8166 PetscScalar *r; 8167 PetscMPIInt rank; 8168 DMPolytopeType ct; 8169 PetscInt dim, cStart, cEnd, c; 8170 PetscBool simplex; 8171 8172 PetscFunctionBeginUser; 8173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8174 PetscValidPointer(ranks, 2); 8175 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8176 PetscCall(DMClone(dm, &rdm)); 8177 PetscCall(DMGetDimension(rdm, &dim)); 8178 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8179 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8180 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8181 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8182 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8183 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8184 PetscCall(PetscFEDestroy(&fe)); 8185 PetscCall(DMCreateDS(rdm)); 8186 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8187 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8188 PetscCall(VecGetArray(*ranks, &r)); 8189 for (c = cStart; c < cEnd; ++c) { 8190 PetscScalar *lr; 8191 8192 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8193 if (lr) *lr = rank; 8194 } 8195 PetscCall(VecRestoreArray(*ranks, &r)); 8196 PetscCall(DMDestroy(&rdm)); 8197 PetscFunctionReturn(0); 8198 } 8199 8200 /*@ 8201 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8202 8203 Input Parameters: 8204 + dm - The DMPlex 8205 - label - The DMLabel 8206 8207 Output Parameter: 8208 . val - The label value field 8209 8210 Options Database Keys: 8211 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8212 8213 Level: intermediate 8214 8215 .seealso: DMView() 8216 @*/ 8217 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8218 { 8219 DM rdm; 8220 PetscFE fe; 8221 PetscScalar *v; 8222 PetscInt dim, cStart, cEnd, c; 8223 8224 PetscFunctionBeginUser; 8225 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8226 PetscValidPointer(label, 2); 8227 PetscValidPointer(val, 3); 8228 PetscCall(DMClone(dm, &rdm)); 8229 PetscCall(DMGetDimension(rdm, &dim)); 8230 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8231 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8232 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8233 PetscCall(PetscFEDestroy(&fe)); 8234 PetscCall(DMCreateDS(rdm)); 8235 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8236 PetscCall(DMCreateGlobalVector(rdm, val)); 8237 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8238 PetscCall(VecGetArray(*val, &v)); 8239 for (c = cStart; c < cEnd; ++c) { 8240 PetscScalar *lv; 8241 PetscInt cval; 8242 8243 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8244 PetscCall(DMLabelGetValue(label, c, &cval)); 8245 *lv = cval; 8246 } 8247 PetscCall(VecRestoreArray(*val, &v)); 8248 PetscCall(DMDestroy(&rdm)); 8249 PetscFunctionReturn(0); 8250 } 8251 8252 /*@ 8253 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8254 8255 Input Parameter: 8256 . dm - The DMPlex object 8257 8258 Notes: 8259 This is a useful diagnostic when creating meshes programmatically. 8260 8261 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8262 8263 Level: developer 8264 8265 .seealso: DMCreate(), DMSetFromOptions() 8266 @*/ 8267 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8268 { 8269 PetscSection coneSection, supportSection; 8270 const PetscInt *cone, *support; 8271 PetscInt coneSize, c, supportSize, s; 8272 PetscInt pStart, pEnd, p, pp, csize, ssize; 8273 PetscBool storagecheck = PETSC_TRUE; 8274 8275 PetscFunctionBegin; 8276 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8277 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8278 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8279 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8280 /* Check that point p is found in the support of its cone points, and vice versa */ 8281 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8282 for (p = pStart; p < pEnd; ++p) { 8283 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8284 PetscCall(DMPlexGetCone(dm, p, &cone)); 8285 for (c = 0; c < coneSize; ++c) { 8286 PetscBool dup = PETSC_FALSE; 8287 PetscInt d; 8288 for (d = c-1; d >= 0; --d) { 8289 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8290 } 8291 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8292 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8293 for (s = 0; s < supportSize; ++s) { 8294 if (support[s] == p) break; 8295 } 8296 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8297 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p)); 8298 for (s = 0; s < coneSize; ++s) { 8299 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s])); 8300 } 8301 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c])); 8303 for (s = 0; s < supportSize; ++s) { 8304 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s])); 8305 } 8306 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8307 PetscCheck(!dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]); 8308 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]); 8309 } 8310 } 8311 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8312 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8313 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8314 PetscCall(DMPlexGetSupport(dm, p, &support)); 8315 for (s = 0; s < supportSize; ++s) { 8316 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8317 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8318 for (c = 0; c < coneSize; ++c) { 8319 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8320 if (cone[c] != pp) { c = 0; break; } 8321 if (cone[c] == p) break; 8322 } 8323 if (c >= coneSize) { 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p)); 8325 for (c = 0; c < supportSize; ++c) { 8326 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c])); 8327 } 8328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s])); 8330 for (c = 0; c < coneSize; ++c) { 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c])); 8332 } 8333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8334 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]); 8335 } 8336 } 8337 } 8338 if (storagecheck) { 8339 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8340 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8341 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize); 8342 } 8343 PetscFunctionReturn(0); 8344 } 8345 8346 /* 8347 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. 8348 */ 8349 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8350 { 8351 DMPolytopeType cct; 8352 PetscInt ptpoints[4]; 8353 const PetscInt *cone, *ccone, *ptcone; 8354 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8355 8356 PetscFunctionBegin; 8357 *unsplit = 0; 8358 switch (ct) { 8359 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8360 ptpoints[npt++] = c; 8361 break; 8362 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8363 PetscCall(DMPlexGetCone(dm, c, &cone)); 8364 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8365 for (cp = 0; cp < coneSize; ++cp) { 8366 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8367 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8368 } 8369 break; 8370 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8371 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8372 PetscCall(DMPlexGetCone(dm, c, &cone)); 8373 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8374 for (cp = 0; cp < coneSize; ++cp) { 8375 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8376 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8377 for (ccp = 0; ccp < cconeSize; ++ccp) { 8378 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8379 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8380 PetscInt p; 8381 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8382 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8383 } 8384 } 8385 } 8386 break; 8387 default: break; 8388 } 8389 for (pt = 0; pt < npt; ++pt) { 8390 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8391 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8392 } 8393 PetscFunctionReturn(0); 8394 } 8395 8396 /*@ 8397 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8398 8399 Input Parameters: 8400 + dm - The DMPlex object 8401 - cellHeight - Normally 0 8402 8403 Notes: 8404 This is a useful diagnostic when creating meshes programmatically. 8405 Currently applicable only to homogeneous simplex or tensor meshes. 8406 8407 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8408 8409 Level: developer 8410 8411 .seealso: DMCreate(), DMSetFromOptions() 8412 @*/ 8413 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8414 { 8415 DMPlexInterpolatedFlag interp; 8416 DMPolytopeType ct; 8417 PetscInt vStart, vEnd, cStart, cEnd, c; 8418 8419 PetscFunctionBegin; 8420 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8421 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8422 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8423 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8424 for (c = cStart; c < cEnd; ++c) { 8425 PetscInt *closure = NULL; 8426 PetscInt coneSize, closureSize, cl, Nv = 0; 8427 8428 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8429 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c); 8430 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8431 if (interp == DMPLEX_INTERPOLATED_FULL) { 8432 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8433 PetscCheck(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)); 8434 } 8435 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8436 for (cl = 0; cl < closureSize*2; cl += 2) { 8437 const PetscInt p = closure[cl]; 8438 if ((p >= vStart) && (p < vEnd)) ++Nv; 8439 } 8440 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8441 /* Special Case: Tensor faces with identified vertices */ 8442 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8443 PetscInt unsplit; 8444 8445 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8446 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8447 } 8448 PetscCheck(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)); 8449 } 8450 PetscFunctionReturn(0); 8451 } 8452 8453 /*@ 8454 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8455 8456 Not Collective 8457 8458 Input Parameters: 8459 + dm - The DMPlex object 8460 - cellHeight - Normally 0 8461 8462 Notes: 8463 This is a useful diagnostic when creating meshes programmatically. 8464 This routine is only relevant for meshes that are fully interpolated across all ranks. 8465 It will error out if a partially interpolated mesh is given on some rank. 8466 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8467 8468 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8469 8470 Level: developer 8471 8472 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 8473 @*/ 8474 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8475 { 8476 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8477 DMPlexInterpolatedFlag interpEnum; 8478 8479 PetscFunctionBegin; 8480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8481 PetscCall(DMPlexIsInterpolated(dm, &interpEnum)); 8482 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8483 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 8484 PetscMPIInt rank; 8485 MPI_Comm comm; 8486 8487 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8488 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8489 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 8490 } 8491 8492 PetscCall(DMGetDimension(dm, &dim)); 8493 PetscCall(DMPlexGetDepth(dm, &depth)); 8494 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8495 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8496 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8497 for (c = cStart; c < cEnd; ++c) { 8498 const PetscInt *cone, *ornt, *faceSizes, *faces; 8499 const DMPolytopeType *faceTypes; 8500 DMPolytopeType ct; 8501 PetscInt numFaces, coneSize, f; 8502 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8503 8504 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8505 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8506 if (unsplit) continue; 8507 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8508 PetscCall(DMPlexGetCone(dm, c, &cone)); 8509 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8510 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8511 for (cl = 0; cl < closureSize*2; cl += 2) { 8512 const PetscInt p = closure[cl]; 8513 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8514 } 8515 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8516 PetscCheck(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); 8517 for (f = 0; f < numFaces; ++f) { 8518 DMPolytopeType fct; 8519 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8520 8521 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8522 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8523 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8524 const PetscInt p = fclosure[cl]; 8525 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8526 } 8527 PetscCheck(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]); 8528 for (v = 0; v < fnumCorners; ++v) { 8529 if (fclosure[v] != faces[fOff+v]) { 8530 PetscInt v1; 8531 8532 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8533 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1])); 8534 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8535 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1])); 8536 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8537 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]); 8538 } 8539 } 8540 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8541 fOff += faceSizes[f]; 8542 } 8543 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8544 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8545 } 8546 } 8547 PetscFunctionReturn(0); 8548 } 8549 8550 /*@ 8551 DMPlexCheckGeometry - Check the geometry of mesh cells 8552 8553 Input Parameter: 8554 . dm - The DMPlex object 8555 8556 Notes: 8557 This is a useful diagnostic when creating meshes programmatically. 8558 8559 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8560 8561 Level: developer 8562 8563 .seealso: DMCreate(), DMSetFromOptions() 8564 @*/ 8565 PetscErrorCode DMPlexCheckGeometry(DM dm) 8566 { 8567 Vec coordinates; 8568 PetscReal detJ, J[9], refVol = 1.0; 8569 PetscReal vol; 8570 PetscBool periodic; 8571 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8572 8573 PetscFunctionBegin; 8574 PetscCall(DMGetDimension(dm, &dim)); 8575 PetscCall(DMGetCoordinateDim(dm, &dE)); 8576 if (dim != dE) PetscFunctionReturn(0); 8577 PetscCall(DMPlexGetDepth(dm, &depth)); 8578 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8579 for (d = 0; d < dim; ++d) refVol *= 2.0; 8580 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8581 /* Make sure local coordinates are created, because that step is collective */ 8582 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8583 for (c = cStart; c < cEnd; ++c) { 8584 DMPolytopeType ct; 8585 PetscInt unsplit; 8586 PetscBool ignoreZeroVol = PETSC_FALSE; 8587 8588 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8589 switch (ct) { 8590 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8591 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8592 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8593 ignoreZeroVol = PETSC_TRUE; break; 8594 default: break; 8595 } 8596 switch (ct) { 8597 case DM_POLYTOPE_TRI_PRISM: 8598 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8599 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8600 case DM_POLYTOPE_PYRAMID: 8601 continue; 8602 default: break; 8603 } 8604 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8605 if (unsplit) continue; 8606 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8607 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); 8608 PetscCall(PetscInfo(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol)); 8609 if (depth > 1 && !periodic) { 8610 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8611 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); 8612 PetscCall(PetscInfo(dm, "Cell %D FVM Volume %g\n", c, (double) vol)); 8613 } 8614 } 8615 PetscFunctionReturn(0); 8616 } 8617 8618 /*@ 8619 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 8620 8621 Input Parameters: 8622 . dm - The DMPlex object 8623 8624 Notes: 8625 This is mainly intended for debugging/testing purposes. 8626 It currently checks only meshes with no partition overlapping. 8627 8628 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8629 8630 Level: developer 8631 8632 .seealso: DMGetPointSF(), DMSetFromOptions() 8633 @*/ 8634 PetscErrorCode DMPlexCheckPointSF(DM dm) 8635 { 8636 PetscSF pointSF; 8637 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 8638 const PetscInt *locals, *rootdegree; 8639 PetscBool distributed; 8640 8641 PetscFunctionBegin; 8642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8643 PetscCall(DMGetPointSF(dm, &pointSF)); 8644 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8645 if (!distributed) PetscFunctionReturn(0); 8646 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8647 if (overlap) { 8648 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping")); 8649 PetscFunctionReturn(0); 8650 } 8651 PetscCheck(pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 8652 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL)); 8653 PetscCheck(nroots >= 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 8654 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8655 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8656 8657 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 8658 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8659 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8660 for (l = 0; l < nleaves; ++l) { 8661 const PetscInt point = locals[l]; 8662 8663 PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point); 8664 } 8665 8666 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8667 for (l = 0; l < nleaves; ++l) { 8668 const PetscInt point = locals[l]; 8669 const PetscInt *cone; 8670 PetscInt coneSize, c, idx; 8671 8672 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8673 PetscCall(DMPlexGetCone(dm, point, &cone)); 8674 for (c = 0; c < coneSize; ++c) { 8675 if (!rootdegree[cone[c]]) { 8676 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8677 PetscCheck(idx >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]); 8678 } 8679 } 8680 } 8681 PetscFunctionReturn(0); 8682 } 8683 8684 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight) 8685 { 8686 PetscFunctionBegin; 8687 PetscCall(DMPlexCheckSymmetry(dm)); 8688 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8689 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8690 PetscCall(DMPlexCheckGeometry(dm)); 8691 PetscCall(DMPlexCheckPointSF(dm)); 8692 PetscCall(DMPlexCheckInterfaceCones(dm)); 8693 PetscFunctionReturn(0); 8694 } 8695 8696 typedef struct cell_stats 8697 { 8698 PetscReal min, max, sum, squaresum; 8699 PetscInt count; 8700 } cell_stats_t; 8701 8702 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8703 { 8704 PetscInt i, N = *len; 8705 8706 for (i = 0; i < N; i++) { 8707 cell_stats_t *A = (cell_stats_t *) a; 8708 cell_stats_t *B = (cell_stats_t *) b; 8709 8710 B->min = PetscMin(A->min,B->min); 8711 B->max = PetscMax(A->max,B->max); 8712 B->sum += A->sum; 8713 B->squaresum += A->squaresum; 8714 B->count += A->count; 8715 } 8716 } 8717 8718 /*@ 8719 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8720 8721 Collective on dm 8722 8723 Input Parameters: 8724 + dm - The DMPlex object 8725 . output - If true, statistics will be displayed on stdout 8726 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8727 8728 Notes: 8729 This is mainly intended for debugging/testing purposes. 8730 8731 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8732 8733 Level: developer 8734 8735 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality() 8736 @*/ 8737 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8738 { 8739 DM dmCoarse; 8740 cell_stats_t stats, globalStats; 8741 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8742 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8743 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8744 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8745 PetscMPIInt rank,size; 8746 8747 PetscFunctionBegin; 8748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8749 stats.min = PETSC_MAX_REAL; 8750 stats.max = PETSC_MIN_REAL; 8751 stats.sum = stats.squaresum = 0.; 8752 stats.count = 0; 8753 8754 PetscCallMPI(MPI_Comm_size(comm, &size)); 8755 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8756 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8757 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8758 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8759 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8760 for (c = cStart; c < cEnd; c++) { 8761 PetscInt i; 8762 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8763 8764 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8765 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c); 8766 for (i = 0; i < PetscSqr(cdim); ++i) { 8767 frobJ += J[i] * J[i]; 8768 frobInvJ += invJ[i] * invJ[i]; 8769 } 8770 cond2 = frobJ * frobInvJ; 8771 cond = PetscSqrtReal(cond2); 8772 8773 stats.min = PetscMin(stats.min,cond); 8774 stats.max = PetscMax(stats.max,cond); 8775 stats.sum += cond; 8776 stats.squaresum += cond2; 8777 stats.count++; 8778 if (output && cond > limit) { 8779 PetscSection coordSection; 8780 Vec coordsLocal; 8781 PetscScalar *coords = NULL; 8782 PetscInt Nv, d, clSize, cl, *closure = NULL; 8783 8784 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8785 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8786 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8787 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond)); 8788 for (i = 0; i < Nv/cdim; ++i) { 8789 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %D: (", i)); 8790 for (d = 0; d < cdim; ++d) { 8791 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8792 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8793 } 8794 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8795 } 8796 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8797 for (cl = 0; cl < clSize*2; cl += 2) { 8798 const PetscInt edge = closure[cl]; 8799 8800 if ((edge >= eStart) && (edge < eEnd)) { 8801 PetscReal len; 8802 8803 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8804 PetscCall(PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len)); 8805 } 8806 } 8807 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8808 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8809 } 8810 } 8811 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8812 8813 if (size > 1) { 8814 PetscMPIInt blockLengths[2] = {4,1}; 8815 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8816 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8817 MPI_Op statReduce; 8818 8819 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8820 PetscCallMPI(MPI_Type_commit(&statType)); 8821 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8822 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8823 PetscCallMPI(MPI_Op_free(&statReduce)); 8824 PetscCallMPI(MPI_Type_free(&statType)); 8825 } else { 8826 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8827 } 8828 if (rank == 0) { 8829 count = globalStats.count; 8830 min = globalStats.min; 8831 max = globalStats.max; 8832 mean = globalStats.sum / globalStats.count; 8833 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8834 } 8835 8836 if (output) { 8837 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)); 8838 } 8839 PetscCall(PetscFree2(J,invJ)); 8840 8841 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8842 if (dmCoarse) { 8843 PetscBool isplex; 8844 8845 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8846 if (isplex) { 8847 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8848 } 8849 } 8850 PetscFunctionReturn(0); 8851 } 8852 8853 /*@ 8854 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8855 orthogonal quality below given tolerance. 8856 8857 Collective on dm 8858 8859 Input Parameters: 8860 + dm - The DMPlex object 8861 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8862 - atol - [0, 1] Absolute tolerance for tagging cells. 8863 8864 Output Parameters: 8865 + OrthQual - Vec containing orthogonal quality per cell 8866 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8867 8868 Options Database Keys: 8869 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8870 supported. 8871 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8872 8873 Notes: 8874 Orthogonal quality is given by the following formula: 8875 8876 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8877 8878 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 8879 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8880 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8881 calculating the cosine of the angle between these vectors. 8882 8883 Orthogonal quality ranges from 1 (best) to 0 (worst). 8884 8885 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8886 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8887 8888 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8889 8890 Level: intermediate 8891 8892 .seealso: DMPlexCheckCellShape(), DMCreateLabel() 8893 @*/ 8894 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8895 { 8896 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8897 PetscInt *idx; 8898 PetscScalar *oqVals; 8899 const PetscScalar *cellGeomArr, *faceGeomArr; 8900 PetscReal *ci, *fi, *Ai; 8901 MPI_Comm comm; 8902 Vec cellgeom, facegeom; 8903 DM dmFace, dmCell; 8904 IS glob; 8905 ISLocalToGlobalMapping ltog; 8906 PetscViewer vwr; 8907 8908 PetscFunctionBegin; 8909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8910 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8911 PetscValidPointer(OrthQual, 4); 8912 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8913 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8914 PetscCall(DMGetDimension(dm, &nc)); 8915 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc); 8916 { 8917 DMPlexInterpolatedFlag interpFlag; 8918 8919 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8920 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8921 PetscMPIInt rank; 8922 8923 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8924 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8925 } 8926 } 8927 if (OrthQualLabel) { 8928 PetscValidPointer(OrthQualLabel, 5); 8929 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8930 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8931 } else {*OrthQualLabel = NULL;} 8932 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8933 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8934 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8935 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8936 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8937 PetscCall(VecCreate(comm, OrthQual)); 8938 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8939 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 8940 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8941 PetscCall(VecSetUp(*OrthQual)); 8942 PetscCall(ISDestroy(&glob)); 8943 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8944 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8945 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8946 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8947 PetscCall(VecGetDM(cellgeom, &dmCell)); 8948 PetscCall(VecGetDM(facegeom, &dmFace)); 8949 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8950 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 8951 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8952 PetscInt cellarr[2], *adj = NULL; 8953 PetscScalar *cArr, *fArr; 8954 PetscReal minvalc = 1.0, minvalf = 1.0; 8955 PetscFVCellGeom *cg; 8956 8957 idx[cellIter] = cell-cStart; 8958 cellarr[0] = cell; 8959 /* Make indexing into cellGeom easier */ 8960 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8961 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8962 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8963 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8964 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 8965 PetscInt i; 8966 const PetscInt neigh = adj[cellneigh]; 8967 PetscReal normci = 0, normfi = 0, normai = 0; 8968 PetscFVCellGeom *cgneigh; 8969 PetscFVFaceGeom *fg; 8970 8971 /* Don't count ourselves in the neighbor list */ 8972 if (neigh == cell) continue; 8973 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8974 cellarr[1] = neigh; 8975 { 8976 PetscInt numcovpts; 8977 const PetscInt *covpts; 8978 8979 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8980 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8981 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8982 } 8983 8984 /* Compute c_i, f_i and their norms */ 8985 for (i = 0; i < nc; i++) { 8986 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8987 fi[i] = fg->centroid[i] - cg->centroid[i]; 8988 Ai[i] = fg->normal[i]; 8989 normci += PetscPowReal(ci[i], 2); 8990 normfi += PetscPowReal(fi[i], 2); 8991 normai += PetscPowReal(Ai[i], 2); 8992 } 8993 normci = PetscSqrtReal(normci); 8994 normfi = PetscSqrtReal(normfi); 8995 normai = PetscSqrtReal(normai); 8996 8997 /* Normalize and compute for each face-cell-normal pair */ 8998 for (i = 0; i < nc; i++) { 8999 ci[i] = ci[i]/normci; 9000 fi[i] = fi[i]/normfi; 9001 Ai[i] = Ai[i]/normai; 9002 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9003 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9004 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9005 } 9006 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9007 minvalc = PetscRealPart(cArr[cellneighiter]); 9008 } 9009 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9010 minvalf = PetscRealPart(fArr[cellneighiter]); 9011 } 9012 } 9013 PetscCall(PetscFree(adj)); 9014 PetscCall(PetscFree2(cArr, fArr)); 9015 /* Defer to cell if they're equal */ 9016 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9017 if (OrthQualLabel) { 9018 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9019 } 9020 } 9021 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9022 PetscCall(VecAssemblyBegin(*OrthQual)); 9023 PetscCall(VecAssemblyEnd(*OrthQual)); 9024 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9025 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9026 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9027 if (OrthQualLabel) { 9028 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9029 } 9030 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9031 PetscCall(PetscViewerDestroy(&vwr)); 9032 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9033 PetscFunctionReturn(0); 9034 } 9035 9036 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9037 * interpolator construction */ 9038 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9039 { 9040 PetscSection section, newSection, gsection; 9041 PetscSF sf; 9042 PetscBool hasConstraints, ghasConstraints; 9043 9044 PetscFunctionBegin; 9045 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9046 PetscValidPointer(odm,2); 9047 PetscCall(DMGetLocalSection(dm, §ion)); 9048 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9049 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9050 if (!ghasConstraints) { 9051 PetscCall(PetscObjectReference((PetscObject)dm)); 9052 *odm = dm; 9053 PetscFunctionReturn(0); 9054 } 9055 PetscCall(DMClone(dm, odm)); 9056 PetscCall(DMCopyFields(dm, *odm)); 9057 PetscCall(DMGetLocalSection(*odm, &newSection)); 9058 PetscCall(DMGetPointSF(*odm, &sf)); 9059 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9060 PetscCall(DMSetGlobalSection(*odm, gsection)); 9061 PetscCall(PetscSectionDestroy(&gsection)); 9062 PetscFunctionReturn(0); 9063 } 9064 9065 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9066 { 9067 DM dmco, dmfo; 9068 Mat interpo; 9069 Vec rscale; 9070 Vec cglobalo, clocal; 9071 Vec fglobal, fglobalo, flocal; 9072 PetscBool regular; 9073 9074 PetscFunctionBegin; 9075 PetscCall(DMGetFullDM(dmc, &dmco)); 9076 PetscCall(DMGetFullDM(dmf, &dmfo)); 9077 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9078 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9079 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9080 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9081 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9082 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9083 PetscCall(VecSet(cglobalo, 0.)); 9084 PetscCall(VecSet(clocal, 0.)); 9085 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9086 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9087 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9088 PetscCall(VecSet(fglobal, 0.)); 9089 PetscCall(VecSet(fglobalo, 0.)); 9090 PetscCall(VecSet(flocal, 0.)); 9091 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9092 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9093 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9094 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9095 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9096 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9097 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9098 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9099 *shift = fglobal; 9100 PetscCall(VecDestroy(&flocal)); 9101 PetscCall(VecDestroy(&fglobalo)); 9102 PetscCall(VecDestroy(&clocal)); 9103 PetscCall(VecDestroy(&cglobalo)); 9104 PetscCall(VecDestroy(&rscale)); 9105 PetscCall(MatDestroy(&interpo)); 9106 PetscCall(DMDestroy(&dmfo)); 9107 PetscCall(DMDestroy(&dmco)); 9108 PetscFunctionReturn(0); 9109 } 9110 9111 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9112 { 9113 PetscObject shifto; 9114 Vec shift; 9115 9116 PetscFunctionBegin; 9117 if (!interp) { 9118 Vec rscale; 9119 9120 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9121 PetscCall(VecDestroy(&rscale)); 9122 } else { 9123 PetscCall(PetscObjectReference((PetscObject)interp)); 9124 } 9125 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9126 if (!shifto) { 9127 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9128 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9129 shifto = (PetscObject) shift; 9130 PetscCall(VecDestroy(&shift)); 9131 } 9132 shift = (Vec) shifto; 9133 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9134 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9135 PetscCall(MatDestroy(&interp)); 9136 PetscFunctionReturn(0); 9137 } 9138 9139 /* Pointwise interpolation 9140 Just code FEM for now 9141 u^f = I u^c 9142 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9143 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9144 I_{ij} = psi^f_i phi^c_j 9145 */ 9146 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9147 { 9148 PetscSection gsc, gsf; 9149 PetscInt m, n; 9150 void *ctx; 9151 DM cdm; 9152 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9153 9154 PetscFunctionBegin; 9155 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9156 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9157 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9158 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9159 9160 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9161 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9162 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9163 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9164 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9165 9166 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9167 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9168 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9169 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9170 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9171 if (scaling) { 9172 /* Use naive scaling */ 9173 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9174 } 9175 PetscFunctionReturn(0); 9176 } 9177 9178 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9179 { 9180 VecScatter ctx; 9181 9182 PetscFunctionBegin; 9183 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9184 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9185 PetscCall(VecScatterDestroy(&ctx)); 9186 PetscFunctionReturn(0); 9187 } 9188 9189 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9190 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9191 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9192 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9193 { 9194 const PetscInt Nc = uOff[1] - uOff[0]; 9195 PetscInt c; 9196 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9197 } 9198 9199 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9200 { 9201 DM dmc; 9202 PetscDS ds; 9203 Vec ones, locmass; 9204 IS cellIS; 9205 PetscFormKey key; 9206 PetscInt depth; 9207 9208 PetscFunctionBegin; 9209 PetscCall(DMClone(dm, &dmc)); 9210 PetscCall(DMCopyDisc(dm, dmc)); 9211 PetscCall(DMGetDS(dmc, &ds)); 9212 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9213 PetscCall(DMCreateGlobalVector(dmc, mass)); 9214 PetscCall(DMGetLocalVector(dmc, &ones)); 9215 PetscCall(DMGetLocalVector(dmc, &locmass)); 9216 PetscCall(DMPlexGetDepth(dmc, &depth)); 9217 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9218 PetscCall(VecSet(locmass, 0.0)); 9219 PetscCall(VecSet(ones, 1.0)); 9220 key.label = NULL; 9221 key.value = 0; 9222 key.field = 0; 9223 key.part = 0; 9224 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9225 PetscCall(ISDestroy(&cellIS)); 9226 PetscCall(VecSet(*mass, 0.0)); 9227 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9228 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9229 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9230 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9231 PetscCall(DMDestroy(&dmc)); 9232 PetscFunctionReturn(0); 9233 } 9234 9235 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9236 { 9237 PetscSection gsc, gsf; 9238 PetscInt m, n; 9239 void *ctx; 9240 DM cdm; 9241 PetscBool regular; 9242 9243 PetscFunctionBegin; 9244 if (dmFine == dmCoarse) { 9245 DM dmc; 9246 PetscDS ds; 9247 PetscWeakForm wf; 9248 Vec u; 9249 IS cellIS; 9250 PetscFormKey key; 9251 PetscInt depth; 9252 9253 PetscCall(DMClone(dmFine, &dmc)); 9254 PetscCall(DMCopyDisc(dmFine, dmc)); 9255 PetscCall(DMGetDS(dmc, &ds)); 9256 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9257 PetscCall(PetscWeakFormClear(wf)); 9258 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9259 PetscCall(DMCreateMatrix(dmc, mass)); 9260 PetscCall(DMGetGlobalVector(dmc, &u)); 9261 PetscCall(DMPlexGetDepth(dmc, &depth)); 9262 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9263 PetscCall(MatZeroEntries(*mass)); 9264 key.label = NULL; 9265 key.value = 0; 9266 key.field = 0; 9267 key.part = 0; 9268 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9269 PetscCall(ISDestroy(&cellIS)); 9270 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9271 PetscCall(DMDestroy(&dmc)); 9272 } else { 9273 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9274 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9275 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9276 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9277 9278 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9279 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9280 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9281 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9282 9283 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9284 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9285 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9286 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9287 } 9288 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9289 PetscFunctionReturn(0); 9290 } 9291 9292 /*@ 9293 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9294 9295 Input Parameter: 9296 . dm - The DMPlex object 9297 9298 Output Parameter: 9299 . regular - The flag 9300 9301 Level: intermediate 9302 9303 .seealso: DMPlexSetRegularRefinement() 9304 @*/ 9305 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9306 { 9307 PetscFunctionBegin; 9308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9309 PetscValidBoolPointer(regular, 2); 9310 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9311 PetscFunctionReturn(0); 9312 } 9313 9314 /*@ 9315 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9316 9317 Input Parameters: 9318 + dm - The DMPlex object 9319 - regular - The flag 9320 9321 Level: intermediate 9322 9323 .seealso: DMPlexGetRegularRefinement() 9324 @*/ 9325 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9326 { 9327 PetscFunctionBegin; 9328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9329 ((DM_Plex *) dm->data)->regularRefinement = regular; 9330 PetscFunctionReturn(0); 9331 } 9332 9333 /* anchors */ 9334 /*@ 9335 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9336 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9337 9338 not collective 9339 9340 Input Parameter: 9341 . dm - The DMPlex object 9342 9343 Output Parameters: 9344 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9345 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9346 9347 Level: intermediate 9348 9349 .seealso: DMPlexSetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9350 @*/ 9351 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9352 { 9353 DM_Plex *plex = (DM_Plex *)dm->data; 9354 9355 PetscFunctionBegin; 9356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9357 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9358 if (anchorSection) *anchorSection = plex->anchorSection; 9359 if (anchorIS) *anchorIS = plex->anchorIS; 9360 PetscFunctionReturn(0); 9361 } 9362 9363 /*@ 9364 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9365 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9366 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9367 9368 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9369 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9370 9371 collective on dm 9372 9373 Input Parameters: 9374 + dm - The DMPlex object 9375 . 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). 9376 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9377 9378 The reference counts of anchorSection and anchorIS are incremented. 9379 9380 Level: intermediate 9381 9382 .seealso: DMPlexGetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9383 @*/ 9384 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9385 { 9386 DM_Plex *plex = (DM_Plex *)dm->data; 9387 PetscMPIInt result; 9388 9389 PetscFunctionBegin; 9390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9391 if (anchorSection) { 9392 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9393 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9394 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9395 } 9396 if (anchorIS) { 9397 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9398 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9399 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9400 } 9401 9402 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9403 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9404 plex->anchorSection = anchorSection; 9405 9406 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9407 PetscCall(ISDestroy(&plex->anchorIS)); 9408 plex->anchorIS = anchorIS; 9409 9410 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9411 PetscInt size, a, pStart, pEnd; 9412 const PetscInt *anchors; 9413 9414 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9415 PetscCall(ISGetLocalSize(anchorIS,&size)); 9416 PetscCall(ISGetIndices(anchorIS,&anchors)); 9417 for (a = 0; a < size; a++) { 9418 PetscInt p; 9419 9420 p = anchors[a]; 9421 if (p >= pStart && p < pEnd) { 9422 PetscInt dof; 9423 9424 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9425 if (dof) { 9426 9427 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9428 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p); 9429 } 9430 } 9431 } 9432 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9433 } 9434 /* reset the generic constraints */ 9435 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9436 PetscFunctionReturn(0); 9437 } 9438 9439 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9440 { 9441 PetscSection anchorSection; 9442 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9443 9444 PetscFunctionBegin; 9445 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9446 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9447 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9448 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9449 if (numFields) { 9450 PetscInt f; 9451 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9452 9453 for (f = 0; f < numFields; f++) { 9454 PetscInt numComp; 9455 9456 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9457 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9458 } 9459 } 9460 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9461 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9462 pStart = PetscMax(pStart,sStart); 9463 pEnd = PetscMin(pEnd,sEnd); 9464 pEnd = PetscMax(pStart,pEnd); 9465 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9466 for (p = pStart; p < pEnd; p++) { 9467 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9468 if (dof) { 9469 PetscCall(PetscSectionGetDof(section,p,&dof)); 9470 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9471 for (f = 0; f < numFields; f++) { 9472 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9473 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9474 } 9475 } 9476 } 9477 PetscCall(PetscSectionSetUp(*cSec)); 9478 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9479 PetscFunctionReturn(0); 9480 } 9481 9482 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9483 { 9484 PetscSection aSec; 9485 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9486 const PetscInt *anchors; 9487 PetscInt numFields, f; 9488 IS aIS; 9489 MatType mtype; 9490 PetscBool iscuda,iskokkos; 9491 9492 PetscFunctionBegin; 9493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9494 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9495 PetscCall(PetscSectionGetStorageSize(section, &n)); 9496 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9497 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9498 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9499 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9500 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9501 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9502 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9503 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9504 else mtype = MATSEQAIJ; 9505 PetscCall(MatSetType(*cMat,mtype)); 9506 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9507 PetscCall(ISGetIndices(aIS,&anchors)); 9508 /* cSec will be a subset of aSec and section */ 9509 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9510 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9511 PetscCall(PetscMalloc1(m+1,&i)); 9512 i[0] = 0; 9513 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9514 for (p = pStart; p < pEnd; p++) { 9515 PetscInt rDof, rOff, r; 9516 9517 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9518 if (!rDof) continue; 9519 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9520 if (numFields) { 9521 for (f = 0; f < numFields; f++) { 9522 annz = 0; 9523 for (r = 0; r < rDof; r++) { 9524 a = anchors[rOff + r]; 9525 if (a < sStart || a >= sEnd) continue; 9526 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9527 annz += aDof; 9528 } 9529 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9530 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9531 for (q = 0; q < dof; q++) { 9532 i[off + q + 1] = i[off + q] + annz; 9533 } 9534 } 9535 } else { 9536 annz = 0; 9537 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9538 for (q = 0; q < dof; q++) { 9539 a = anchors[rOff + q]; 9540 if (a < sStart || a >= sEnd) continue; 9541 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9542 annz += aDof; 9543 } 9544 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9545 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9546 for (q = 0; q < dof; q++) { 9547 i[off + q + 1] = i[off + q] + annz; 9548 } 9549 } 9550 } 9551 nnz = i[m]; 9552 PetscCall(PetscMalloc1(nnz,&j)); 9553 offset = 0; 9554 for (p = pStart; p < pEnd; p++) { 9555 if (numFields) { 9556 for (f = 0; f < numFields; f++) { 9557 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9558 for (q = 0; q < dof; q++) { 9559 PetscInt rDof, rOff, r; 9560 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9561 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9562 for (r = 0; r < rDof; r++) { 9563 PetscInt s; 9564 9565 a = anchors[rOff + r]; 9566 if (a < sStart || a >= sEnd) continue; 9567 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9568 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9569 for (s = 0; s < aDof; s++) { 9570 j[offset++] = aOff + s; 9571 } 9572 } 9573 } 9574 } 9575 } else { 9576 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9577 for (q = 0; q < dof; q++) { 9578 PetscInt rDof, rOff, r; 9579 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9580 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9581 for (r = 0; r < rDof; r++) { 9582 PetscInt s; 9583 9584 a = anchors[rOff + r]; 9585 if (a < sStart || a >= sEnd) continue; 9586 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9587 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9588 for (s = 0; s < aDof; s++) { 9589 j[offset++] = aOff + s; 9590 } 9591 } 9592 } 9593 } 9594 } 9595 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9596 PetscCall(PetscFree(i)); 9597 PetscCall(PetscFree(j)); 9598 PetscCall(ISRestoreIndices(aIS,&anchors)); 9599 PetscFunctionReturn(0); 9600 } 9601 9602 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9603 { 9604 DM_Plex *plex = (DM_Plex *)dm->data; 9605 PetscSection anchorSection, section, cSec; 9606 Mat cMat; 9607 9608 PetscFunctionBegin; 9609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9610 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9611 if (anchorSection) { 9612 PetscInt Nf; 9613 9614 PetscCall(DMGetLocalSection(dm,§ion)); 9615 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9616 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9617 PetscCall(DMGetNumFields(dm,&Nf)); 9618 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9619 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9620 PetscCall(PetscSectionDestroy(&cSec)); 9621 PetscCall(MatDestroy(&cMat)); 9622 } 9623 PetscFunctionReturn(0); 9624 } 9625 9626 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9627 { 9628 IS subis; 9629 PetscSection section, subsection; 9630 9631 PetscFunctionBegin; 9632 PetscCall(DMGetLocalSection(dm, §ion)); 9633 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9634 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9635 /* Create subdomain */ 9636 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9637 /* Create submodel */ 9638 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9639 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9640 PetscCall(DMSetLocalSection(*subdm, subsection)); 9641 PetscCall(PetscSectionDestroy(&subsection)); 9642 PetscCall(DMCopyDisc(dm, *subdm)); 9643 /* Create map from submodel to global model */ 9644 if (is) { 9645 PetscSection sectionGlobal, subsectionGlobal; 9646 IS spIS; 9647 const PetscInt *spmap; 9648 PetscInt *subIndices; 9649 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9650 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9651 9652 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9653 PetscCall(ISGetIndices(spIS, &spmap)); 9654 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9655 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9656 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9657 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9658 for (p = pStart; p < pEnd; ++p) { 9659 PetscInt gdof, pSubSize = 0; 9660 9661 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9662 if (gdof > 0) { 9663 for (f = 0; f < Nf; ++f) { 9664 PetscInt fdof, fcdof; 9665 9666 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9667 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9668 pSubSize += fdof-fcdof; 9669 } 9670 subSize += pSubSize; 9671 if (pSubSize) { 9672 if (bs < 0) { 9673 bs = pSubSize; 9674 } else if (bs != pSubSize) { 9675 /* Layout does not admit a pointwise block size */ 9676 bs = 1; 9677 } 9678 } 9679 } 9680 } 9681 /* Must have same blocksize on all procs (some might have no points) */ 9682 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9683 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9684 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9685 else {bs = bsMinMax[0];} 9686 PetscCall(PetscMalloc1(subSize, &subIndices)); 9687 for (p = pStart; p < pEnd; ++p) { 9688 PetscInt gdof, goff; 9689 9690 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9691 if (gdof > 0) { 9692 const PetscInt point = spmap[p]; 9693 9694 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9695 for (f = 0; f < Nf; ++f) { 9696 PetscInt fdof, fcdof, fc, f2, poff = 0; 9697 9698 /* Can get rid of this loop by storing field information in the global section */ 9699 for (f2 = 0; f2 < f; ++f2) { 9700 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9701 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9702 poff += fdof-fcdof; 9703 } 9704 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9705 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9706 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9707 subIndices[subOff] = goff+poff+fc; 9708 } 9709 } 9710 } 9711 } 9712 PetscCall(ISRestoreIndices(spIS, &spmap)); 9713 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9714 if (bs > 1) { 9715 /* We need to check that the block size does not come from non-contiguous fields */ 9716 PetscInt i, j, set = 1; 9717 for (i = 0; i < subSize; i += bs) { 9718 for (j = 0; j < bs; ++j) { 9719 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9720 } 9721 } 9722 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9723 } 9724 /* Attach nullspace */ 9725 for (f = 0; f < Nf; ++f) { 9726 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9727 if ((*subdm)->nullspaceConstructors[f]) break; 9728 } 9729 if (f < Nf) { 9730 MatNullSpace nullSpace; 9731 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9732 9733 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9734 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9735 } 9736 } 9737 PetscFunctionReturn(0); 9738 } 9739 9740 /*@ 9741 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9742 9743 Input Parameter: 9744 - dm - The DM 9745 9746 Level: developer 9747 9748 Options Database Keys: 9749 . -dm_plex_monitor_throughput - Activate the monitor 9750 9751 .seealso: DMSetFromOptions(), DMPlexCreate() 9752 @*/ 9753 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9754 { 9755 #if defined(PETSC_USE_LOG) 9756 PetscStageLog stageLog; 9757 PetscLogEvent event; 9758 PetscLogStage stage; 9759 PetscEventPerfInfo eventInfo; 9760 PetscReal cellRate, flopRate; 9761 PetscInt cStart, cEnd, Nf, N; 9762 const char *name; 9763 #endif 9764 9765 PetscFunctionBegin; 9766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9767 #if defined(PETSC_USE_LOG) 9768 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9769 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9770 PetscCall(DMGetNumFields(dm, &Nf)); 9771 PetscCall(PetscLogGetStageLog(&stageLog)); 9772 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9773 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9774 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9775 N = (cEnd - cStart)*Nf*eventInfo.count; 9776 flopRate = eventInfo.flops/eventInfo.time; 9777 cellRate = N/eventInfo.time; 9778 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))); 9779 #else 9780 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9781 #endif 9782 PetscFunctionReturn(0); 9783 } 9784