1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 13 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: `VecViewFromOptions()`, `VecView()` 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 929 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 930 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 931 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 932 if (!useLabels) numLabels = 0; 933 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 934 if (!useColors) { 935 numColors = 3; 936 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 937 } 938 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 939 if (!useColors) { 940 numLColors = 4; 941 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 942 } 943 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 944 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 945 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 946 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 994 } 995 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 996 } 997 if (drawHasse) { 998 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 999 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1001 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1003 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1012 } 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1014 1015 /* Plot vertices */ 1016 PetscCall(VecGetArray(coordinates, &coords)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 for (v = vStart; v < vEnd; ++v) { 1019 PetscInt off, dof, d; 1020 PetscBool isLabeled = PETSC_FALSE; 1021 1022 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1023 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1025 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1026 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1027 for (d = 0; d < dof; ++d) { 1028 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1029 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1030 } 1031 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1032 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1033 for (d = 0; d < dof; ++d) { 1034 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1036 } 1037 if (drawHasse) color = colors[0%numColors]; 1038 else color = colors[rank%numColors]; 1039 for (l = 0; l < numLabels; ++l) { 1040 PetscInt val; 1041 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1042 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1043 } 1044 if (drawNumbers[0]) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1046 } else if (drawColors[0]) { 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1048 } else { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1050 } 1051 } 1052 PetscCall(VecRestoreArray(coordinates, &coords)); 1053 PetscCall(PetscViewerFlush(viewer)); 1054 /* Plot edges */ 1055 if (plotEdges) { 1056 PetscCall(VecGetArray(coordinates, &coords)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1058 for (e = eStart; e < eEnd; ++e) { 1059 const PetscInt *cone; 1060 PetscInt coneSize, offA, offB, dof, d; 1061 1062 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1063 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1064 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1065 PetscCall(DMPlexGetCone(dm, e, &cone)); 1066 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1067 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1068 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1070 for (d = 0; d < dof; ++d) { 1071 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1072 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1073 } 1074 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1075 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1076 for (d = 0; d < dof; ++d) { 1077 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1079 } 1080 if (drawHasse) color = colors[1%numColors]; 1081 else color = colors[rank%numColors]; 1082 for (l = 0; l < numLabels; ++l) { 1083 PetscInt val; 1084 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1085 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1086 } 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1088 } 1089 PetscCall(VecRestoreArray(coordinates, &coords)); 1090 PetscCall(PetscViewerFlush(viewer)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1092 } 1093 /* Plot cells */ 1094 if (dim == 3 || !drawNumbers[1]) { 1095 for (e = eStart; e < eEnd; ++e) { 1096 const PetscInt *cone; 1097 1098 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1099 color = colors[rank%numColors]; 1100 for (l = 0; l < numLabels; ++l) { 1101 PetscInt val; 1102 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1103 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1104 } 1105 PetscCall(DMPlexGetCone(dm, e, &cone)); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1107 } 1108 } else { 1109 DMPolytopeType ct; 1110 1111 /* Drawing a 2D polygon */ 1112 for (c = cStart; c < cEnd; ++c) { 1113 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1115 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1116 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1117 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, e; 1120 1121 PetscCall(DMPlexGetCone(dm, c, &cone)); 1122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1123 for (e = 0; e < coneSize; ++e) { 1124 const PetscInt *econe; 1125 1126 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1127 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1128 } 1129 } else { 1130 PetscInt *closure = NULL; 1131 PetscInt closureSize, Nv = 0, v; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize*2; p += 2) { 1135 const PetscInt point = closure[p]; 1136 1137 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1138 } 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1140 for (v = 0; v <= Nv; ++v) { 1141 const PetscInt vertex = closure[v%Nv]; 1142 1143 if (v > 0) { 1144 if (plotEdges) { 1145 const PetscInt *edge; 1146 PetscInt endpoints[2], ne; 1147 1148 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1149 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1150 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1152 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1153 } else { 1154 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1155 } 1156 } 1157 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1158 } 1159 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 PetscCall(VecGetArray(coordinates, &coords)); 1165 for (c = cStart; c < cEnd; ++c) { 1166 double ccoords[3] = {0.0, 0.0, 0.0}; 1167 PetscBool isLabeled = PETSC_FALSE; 1168 PetscInt *closure = NULL; 1169 PetscInt closureSize, dof, d, n = 0; 1170 1171 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1172 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1174 for (p = 0; p < closureSize*2; p += 2) { 1175 const PetscInt point = closure[p]; 1176 PetscInt off; 1177 1178 if ((point < vStart) || (point >= vEnd)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1181 for (d = 0; d < dof; ++d) { 1182 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1183 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1184 } 1185 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1186 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1187 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1188 ++n; 1189 } 1190 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1191 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1195 } 1196 if (drawHasse) color = colors[depth%numColors]; 1197 else color = colors[rank%numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1201 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1202 } 1203 if (drawNumbers[dim]) { 1204 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1205 } else if (drawColors[dim]) { 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1207 } else { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1209 } 1210 } 1211 PetscCall(VecRestoreArray(coordinates, &coords)); 1212 if (drawHasse) { 1213 color = colors[depth%numColors]; 1214 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1215 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1216 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1217 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1219 1220 color = colors[1%numColors]; 1221 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1226 1227 color = colors[0%numColors]; 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1233 1234 for (p = pStart; p < pEnd; ++p) { 1235 const PetscInt *cone; 1236 PetscInt coneSize, cp; 1237 1238 PetscCall(DMPlexGetCone(dm, p, &cone)); 1239 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1240 for (cp = 0; cp < coneSize; ++cp) { 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1242 } 1243 } 1244 } 1245 PetscCall(PetscViewerFlush(viewer)); 1246 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1249 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1250 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1251 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1252 PetscCall(PetscFree3(names, colors, lcolors)); 1253 PetscCall(PetscBTDestroy(&wp)); 1254 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1255 Vec cown,acown; 1256 VecScatter sct; 1257 ISLocalToGlobalMapping g2l; 1258 IS gid,acis; 1259 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1260 MPI_Group ggroup,ngroup; 1261 PetscScalar *array,nid; 1262 const PetscInt *idxs; 1263 PetscInt *idxs2,*start,*adjacency,*work; 1264 PetscInt64 lm[3],gm[3]; 1265 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1266 PetscMPIInt d1,d2,rank; 1267 1268 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1269 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1270 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1271 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1272 #endif 1273 if (ncomm != MPI_COMM_NULL) { 1274 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1275 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1276 d1 = 0; 1277 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1278 nid = d2; 1279 PetscCallMPI(MPI_Group_free(&ggroup)); 1280 PetscCallMPI(MPI_Group_free(&ngroup)); 1281 PetscCallMPI(MPI_Comm_free(&ncomm)); 1282 } else nid = 0.0; 1283 1284 /* Get connectivity */ 1285 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1286 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1287 1288 /* filter overlapped local cells */ 1289 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1290 PetscCall(ISGetIndices(gid,&idxs)); 1291 PetscCall(ISGetLocalSize(gid,&cum)); 1292 PetscCall(PetscMalloc1(cum,&idxs2)); 1293 for (c = cStart, cum = 0; c < cEnd; c++) { 1294 if (idxs[c-cStart] < 0) continue; 1295 idxs2[cum++] = idxs[c-cStart]; 1296 } 1297 PetscCall(ISRestoreIndices(gid,&idxs)); 1298 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1299 PetscCall(ISDestroy(&gid)); 1300 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1301 1302 /* support for node-aware cell locality */ 1303 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1304 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1305 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1306 PetscCall(VecGetArray(cown,&array)); 1307 for (c = 0; c < numVertices; c++) array[c] = nid; 1308 PetscCall(VecRestoreArray(cown,&array)); 1309 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1310 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1311 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1312 PetscCall(ISDestroy(&acis)); 1313 PetscCall(VecScatterDestroy(&sct)); 1314 PetscCall(VecDestroy(&cown)); 1315 1316 /* compute edgeCut */ 1317 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1318 PetscCall(PetscMalloc1(cum,&work)); 1319 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1320 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1321 PetscCall(ISDestroy(&gid)); 1322 PetscCall(VecGetArray(acown,&array)); 1323 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1324 PetscInt totl; 1325 1326 totl = start[c+1]-start[c]; 1327 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1328 for (i = 0; i < totl; i++) { 1329 if (work[i] < 0) { 1330 ect += 1; 1331 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1332 } 1333 } 1334 } 1335 PetscCall(PetscFree(work)); 1336 PetscCall(VecRestoreArray(acown,&array)); 1337 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1338 lm[1] = -numVertices; 1339 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1340 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1341 lm[0] = ect; /* edgeCut */ 1342 lm[1] = ectn; /* node-aware edgeCut */ 1343 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1344 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1345 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1346 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1347 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1348 #else 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1350 #endif 1351 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1352 PetscCall(PetscFree(start)); 1353 PetscCall(PetscFree(adjacency)); 1354 PetscCall(VecDestroy(&acown)); 1355 } else { 1356 const char *name; 1357 PetscInt *sizes, *hybsizes, *ghostsizes; 1358 PetscInt locDepth, depth, cellHeight, dim, d; 1359 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1360 PetscInt numLabels, l, maxSize = 17; 1361 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1362 MPI_Comm comm; 1363 PetscMPIInt size, rank; 1364 1365 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1366 PetscCallMPI(MPI_Comm_size(comm, &size)); 1367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1368 PetscCall(DMGetDimension(dm, &dim)); 1369 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1370 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1371 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1372 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1373 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1374 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1375 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1376 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1377 gcNum = gcEnd - gcStart; 1378 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1379 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1380 for (d = 0; d <= depth; d++) { 1381 PetscInt Nc[2] = {0, 0}, ict; 1382 1383 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1384 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1385 ict = ct0; 1386 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1387 ct0 = (DMPolytopeType) ict; 1388 for (p = pStart; p < pEnd; ++p) { 1389 DMPolytopeType ct; 1390 1391 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1392 if (ct == ct0) ++Nc[0]; 1393 else ++Nc[1]; 1394 } 1395 if (size < maxSize) { 1396 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1397 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1398 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1400 for (p = 0; p < size; ++p) { 1401 if (rank == 0) { 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1403 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1404 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1405 } 1406 } 1407 } else { 1408 PetscInt locMinMax[2]; 1409 1410 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1411 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1412 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1413 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1414 if (d == depth) { 1415 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1416 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1417 } 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1420 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1421 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1422 } 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1424 } 1425 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1426 { 1427 const PetscReal *maxCell; 1428 const PetscReal *L; 1429 const DMBoundaryType *bd; 1430 PetscBool per, localized; 1431 1432 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1433 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1434 if (per) { 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1436 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1437 for (d = 0; d < dim; ++d) { 1438 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1439 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1440 } 1441 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1442 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1443 } 1444 } 1445 PetscCall(DMGetNumLabels(dm, &numLabels)); 1446 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1447 for (l = 0; l < numLabels; ++l) { 1448 DMLabel label; 1449 const char *name; 1450 IS valueIS; 1451 const PetscInt *values; 1452 PetscInt numValues, v; 1453 1454 PetscCall(DMGetLabelName(dm, l, &name)); 1455 PetscCall(DMGetLabel(dm, name, &label)); 1456 PetscCall(DMLabelGetNumValues(label, &numValues)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1459 PetscCall(ISGetIndices(valueIS, &values)); 1460 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1461 for (v = 0; v < numValues; ++v) { 1462 PetscInt size; 1463 1464 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1465 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1467 } 1468 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1469 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1470 PetscCall(ISRestoreIndices(valueIS, &values)); 1471 PetscCall(ISDestroy(&valueIS)); 1472 } 1473 { 1474 char **labelNames; 1475 PetscInt Nl = numLabels; 1476 PetscBool flg; 1477 1478 PetscCall(PetscMalloc1(Nl, &labelNames)); 1479 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1480 for (l = 0; l < Nl; ++l) { 1481 DMLabel label; 1482 1483 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1484 if (flg) { 1485 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1486 PetscCall(DMLabelView(label, viewer)); 1487 } 1488 PetscCall(PetscFree(labelNames[l])); 1489 } 1490 PetscCall(PetscFree(labelNames)); 1491 } 1492 /* If no fields are specified, people do not want to see adjacency */ 1493 if (dm->Nf) { 1494 PetscInt f; 1495 1496 for (f = 0; f < dm->Nf; ++f) { 1497 const char *name; 1498 1499 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1500 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1501 PetscCall(PetscViewerASCIIPushTab(viewer)); 1502 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1503 if (dm->fields[f].adjacency[0]) { 1504 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1505 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1506 } else { 1507 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1508 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1509 } 1510 PetscCall(PetscViewerASCIIPopTab(viewer)); 1511 } 1512 } 1513 PetscCall(DMGetCoarseDM(dm, &cdm)); 1514 if (cdm) { 1515 PetscCall(PetscViewerASCIIPushTab(viewer)); 1516 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1517 PetscCall(PetscViewerASCIIPopTab(viewer)); 1518 } 1519 } 1520 PetscFunctionReturn(0); 1521 } 1522 1523 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1524 { 1525 DMPolytopeType ct; 1526 PetscMPIInt rank; 1527 PetscInt cdim; 1528 1529 PetscFunctionBegin; 1530 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1531 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1532 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1533 switch (ct) { 1534 case DM_POLYTOPE_SEGMENT: 1535 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1536 switch (cdim) { 1537 case 1: 1538 { 1539 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1540 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1541 1542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1543 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1544 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1545 } 1546 break; 1547 case 2: 1548 { 1549 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1550 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1551 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1556 } 1557 break; 1558 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1559 } 1560 break; 1561 case DM_POLYTOPE_TRIANGLE: 1562 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1563 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1564 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1565 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1569 break; 1570 case DM_POLYTOPE_QUADRILATERAL: 1571 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1572 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1573 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1583 break; 1584 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1585 } 1586 PetscFunctionReturn(0); 1587 } 1588 1589 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1590 { 1591 DMPolytopeType ct; 1592 PetscReal centroid[2] = {0., 0.}; 1593 PetscMPIInt rank; 1594 PetscInt fillColor, v, e, d; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1600 switch (ct) { 1601 case DM_POLYTOPE_TRIANGLE: 1602 { 1603 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1604 1605 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1606 for (e = 0; e < 3; ++e) { 1607 refCoords[0] = refVertices[e*2+0]; 1608 refCoords[1] = refVertices[e*2+1]; 1609 for (d = 1; d <= edgeDiv; ++d) { 1610 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1611 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1612 } 1613 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1614 for (d = 0; d < edgeDiv; ++d) { 1615 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1616 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1617 } 1618 } 1619 } 1620 break; 1621 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1622 } 1623 PetscFunctionReturn(0); 1624 } 1625 1626 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1627 { 1628 PetscDraw draw; 1629 DM cdm; 1630 PetscSection coordSection; 1631 Vec coordinates; 1632 const PetscScalar *coords; 1633 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1634 PetscReal *refCoords, *edgeCoords; 1635 PetscBool isnull, drawAffine = PETSC_TRUE; 1636 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1637 1638 PetscFunctionBegin; 1639 PetscCall(DMGetCoordinateDim(dm, &dim)); 1640 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1641 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1642 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1643 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1644 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1645 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1646 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1647 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1648 1649 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1650 PetscCall(PetscDrawIsNull(draw, &isnull)); 1651 if (isnull) PetscFunctionReturn(0); 1652 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1653 1654 PetscCall(VecGetLocalSize(coordinates, &N)); 1655 PetscCall(VecGetArrayRead(coordinates, &coords)); 1656 for (c = 0; c < N; c += dim) { 1657 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1658 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1659 } 1660 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1661 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1662 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1663 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1664 PetscCall(PetscDrawClear(draw)); 1665 1666 for (c = cStart; c < cEnd; ++c) { 1667 PetscScalar *coords = NULL; 1668 PetscInt numCoords; 1669 1670 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1671 if (drawAffine) { 1672 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1673 } else { 1674 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1675 } 1676 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1677 } 1678 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1679 PetscCall(PetscDrawFlush(draw)); 1680 PetscCall(PetscDrawPause(draw)); 1681 PetscCall(PetscDrawSave(draw)); 1682 PetscFunctionReturn(0); 1683 } 1684 1685 #if defined(PETSC_HAVE_EXODUSII) 1686 #include <exodusII.h> 1687 #include <petscviewerexodusii.h> 1688 #endif 1689 1690 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1691 { 1692 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1693 char name[PETSC_MAX_PATH_LEN]; 1694 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1697 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1698 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1699 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1704 if (iascii) { 1705 PetscViewerFormat format; 1706 PetscCall(PetscViewerGetFormat(viewer, &format)); 1707 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1708 PetscCall(DMPlexView_GLVis(dm, viewer)); 1709 } else { 1710 PetscCall(DMPlexView_Ascii(dm, viewer)); 1711 } 1712 } else if (ishdf5) { 1713 #if defined(PETSC_HAVE_HDF5) 1714 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1715 #else 1716 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1717 #endif 1718 } else if (isvtk) { 1719 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1720 } else if (isdraw) { 1721 PetscCall(DMPlexView_Draw(dm, viewer)); 1722 } else if (isglvis) { 1723 PetscCall(DMPlexView_GLVis(dm, viewer)); 1724 #if defined(PETSC_HAVE_EXODUSII) 1725 } else if (isexodus) { 1726 /* 1727 exodusII requires that all sets be part of exactly one cell set. 1728 If the dm does not have a "Cell Sets" label defined, we create one 1729 with ID 1, containig all cells. 1730 Note that if the Cell Sets label is defined but does not cover all cells, 1731 we may still have a problem. This should probably be checked here or in the viewer; 1732 */ 1733 PetscInt numCS; 1734 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1735 if (!numCS) { 1736 PetscInt cStart, cEnd, c; 1737 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1738 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1739 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1740 } 1741 PetscCall(DMView_PlexExodusII(dm, viewer)); 1742 #endif 1743 } else { 1744 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1745 } 1746 /* Optionally view the partition */ 1747 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1748 if (flg) { 1749 Vec ranks; 1750 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1751 PetscCall(VecView(ranks, viewer)); 1752 PetscCall(VecDestroy(&ranks)); 1753 } 1754 /* Optionally view a label */ 1755 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1756 if (flg) { 1757 DMLabel label; 1758 Vec val; 1759 1760 PetscCall(DMGetLabel(dm, name, &label)); 1761 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1762 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1763 PetscCall(VecView(val, viewer)); 1764 PetscCall(VecDestroy(&val)); 1765 } 1766 PetscFunctionReturn(0); 1767 } 1768 1769 /*@ 1770 DMPlexTopologyView - Saves a DMPlex topology into a file 1771 1772 Collective on DM 1773 1774 Input Parameters: 1775 + dm - The DM whose topology is to be saved 1776 - viewer - The PetscViewer for saving 1777 1778 Level: advanced 1779 1780 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1781 @*/ 1782 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1783 { 1784 PetscBool ishdf5; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1790 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 IS globalPointNumbering; 1797 1798 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1799 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1800 PetscCall(ISDestroy(&globalPointNumbering)); 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1802 #else 1803 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1804 #endif 1805 } 1806 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1807 PetscFunctionReturn(0); 1808 } 1809 1810 /*@ 1811 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1812 1813 Collective on DM 1814 1815 Input Parameters: 1816 + dm - The DM whose coordinates are to be saved 1817 - viewer - The PetscViewer for saving 1818 1819 Level: advanced 1820 1821 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1822 @*/ 1823 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1824 { 1825 PetscBool ishdf5; 1826 1827 PetscFunctionBegin; 1828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1829 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1830 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1831 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1832 if (ishdf5) { 1833 #if defined(PETSC_HAVE_HDF5) 1834 PetscViewerFormat format; 1835 PetscCall(PetscViewerGetFormat(viewer, &format)); 1836 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1837 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1838 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1839 #else 1840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1841 #endif 1842 } 1843 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1844 PetscFunctionReturn(0); 1845 } 1846 1847 /*@ 1848 DMPlexLabelsView - Saves DMPlex labels into a file 1849 1850 Collective on DM 1851 1852 Input Parameters: 1853 + dm - The DM whose labels are to be saved 1854 - viewer - The PetscViewer for saving 1855 1856 Level: advanced 1857 1858 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1859 @*/ 1860 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1861 { 1862 PetscBool ishdf5; 1863 1864 PetscFunctionBegin; 1865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1866 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1867 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1868 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1869 if (ishdf5) { 1870 #if defined(PETSC_HAVE_HDF5) 1871 IS globalPointNumbering; 1872 PetscViewerFormat format; 1873 1874 PetscCall(PetscViewerGetFormat(viewer, &format)); 1875 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1876 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1877 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1878 PetscCall(ISDestroy(&globalPointNumbering)); 1879 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1880 #else 1881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1882 #endif 1883 } 1884 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1885 PetscFunctionReturn(0); 1886 } 1887 1888 /*@ 1889 DMPlexSectionView - Saves a section associated with a DMPlex 1890 1891 Collective on DM 1892 1893 Input Parameters: 1894 + dm - The DM that contains the topology on which the section to be saved is defined 1895 . viewer - The PetscViewer for saving 1896 - sectiondm - The DM that contains the section to be saved 1897 1898 Level: advanced 1899 1900 Notes: 1901 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1902 1903 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1904 1905 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1906 @*/ 1907 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1908 { 1909 PetscBool ishdf5; 1910 1911 PetscFunctionBegin; 1912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1913 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1914 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1916 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1917 if (ishdf5) { 1918 #if defined(PETSC_HAVE_HDF5) 1919 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1920 #else 1921 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1922 #endif 1923 } 1924 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@ 1929 DMPlexGlobalVectorView - Saves a global vector 1930 1931 Collective on DM 1932 1933 Input Parameters: 1934 + dm - The DM that represents the topology 1935 . viewer - The PetscViewer to save data with 1936 . sectiondm - The DM that contains the global section on which vec is defined 1937 - vec - The global vector to be saved 1938 1939 Level: advanced 1940 1941 Notes: 1942 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1943 1944 Typical calling sequence 1945 $ DMCreate(PETSC_COMM_WORLD, &dm); 1946 $ DMSetType(dm, DMPLEX); 1947 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1948 $ DMClone(dm, §iondm); 1949 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1950 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1951 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1952 $ PetscSectionSetChart(section, pStart, pEnd); 1953 $ PetscSectionSetUp(section); 1954 $ DMSetLocalSection(sectiondm, section); 1955 $ PetscSectionDestroy(§ion); 1956 $ DMGetGlobalVector(sectiondm, &vec); 1957 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1958 $ DMPlexTopologyView(dm, viewer); 1959 $ DMPlexSectionView(dm, viewer, sectiondm); 1960 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1961 $ DMRestoreGlobalVector(sectiondm, &vec); 1962 $ DMDestroy(§iondm); 1963 $ DMDestroy(&dm); 1964 1965 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1966 @*/ 1967 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1968 { 1969 PetscBool ishdf5; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1975 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1976 /* Check consistency */ 1977 { 1978 PetscSection section; 1979 PetscBool includesConstraints; 1980 PetscInt m, m1; 1981 1982 PetscCall(VecGetLocalSize(vec, &m1)); 1983 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1984 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1985 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1986 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1987 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1988 } 1989 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1990 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1991 if (ishdf5) { 1992 #if defined(PETSC_HAVE_HDF5) 1993 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1999 PetscFunctionReturn(0); 2000 } 2001 2002 /*@ 2003 DMPlexLocalVectorView - Saves a local vector 2004 2005 Collective on DM 2006 2007 Input Parameters: 2008 + dm - The DM that represents the topology 2009 . viewer - The PetscViewer to save data with 2010 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2011 - vec - The local vector to be saved 2012 2013 Level: advanced 2014 2015 Notes: 2016 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2017 2018 Typical calling sequence 2019 $ DMCreate(PETSC_COMM_WORLD, &dm); 2020 $ DMSetType(dm, DMPLEX); 2021 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2022 $ DMClone(dm, §iondm); 2023 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2024 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2025 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2026 $ PetscSectionSetChart(section, pStart, pEnd); 2027 $ PetscSectionSetUp(section); 2028 $ DMSetLocalSection(sectiondm, section); 2029 $ DMGetLocalVector(sectiondm, &vec); 2030 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 $ DMPlexTopologyView(dm, viewer); 2032 $ DMPlexSectionView(dm, viewer, sectiondm); 2033 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2034 $ DMRestoreLocalVector(sectiondm, &vec); 2035 $ DMDestroy(§iondm); 2036 $ DMDestroy(&dm); 2037 2038 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2039 @*/ 2040 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2072 PetscFunctionReturn(0); 2073 } 2074 2075 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2076 { 2077 PetscBool ishdf5; 2078 2079 PetscFunctionBegin; 2080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2081 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2082 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2088 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2089 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2090 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2091 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2092 PetscFunctionReturn(0); 2093 #else 2094 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2095 #endif 2096 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2097 } 2098 2099 /*@ 2100 DMPlexTopologyLoad - Loads a topology into a DMPlex 2101 2102 Collective on DM 2103 2104 Input Parameters: 2105 + dm - The DM into which the topology is loaded 2106 - viewer - The PetscViewer for the saved topology 2107 2108 Output Parameters: 2109 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2110 2111 Level: advanced 2112 2113 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2114 @*/ 2115 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2123 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2124 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2125 if (ishdf5) { 2126 #if defined(PETSC_HAVE_HDF5) 2127 PetscViewerFormat format; 2128 PetscCall(PetscViewerGetFormat(viewer, &format)); 2129 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2130 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2131 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2132 #else 2133 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2134 #endif 2135 } 2136 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2137 PetscFunctionReturn(0); 2138 } 2139 2140 /*@ 2141 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2142 2143 Collective on DM 2144 2145 Input Parameters: 2146 + dm - The DM into which the coordinates are loaded 2147 . viewer - The PetscViewer for the saved coordinates 2148 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2149 2150 Level: advanced 2151 2152 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2153 @*/ 2154 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2155 { 2156 PetscBool ishdf5; 2157 2158 PetscFunctionBegin; 2159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2160 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2161 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2162 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsLoad - Loads labels into a DMPlex 2181 2182 Collective on DM 2183 2184 Input Parameters: 2185 + dm - The DM into which the labels are loaded 2186 . viewer - The PetscViewer for the saved labels 2187 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2188 2189 Level: advanced 2190 2191 Notes: 2192 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2193 2194 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2195 @*/ 2196 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2197 { 2198 PetscBool ishdf5; 2199 2200 PetscFunctionBegin; 2201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2203 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscViewerFormat format; 2209 2210 PetscCall(PetscViewerGetFormat(viewer, &format)); 2211 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2212 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2213 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2214 #else 2215 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2216 #endif 2217 } 2218 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@ 2223 DMPlexSectionLoad - Loads section into a DMPlex 2224 2225 Collective on DM 2226 2227 Input Parameters: 2228 + dm - The DM that represents the topology 2229 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2230 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2231 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2232 2233 Output Parameters 2234 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2235 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2236 2237 Level: advanced 2238 2239 Notes: 2240 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2241 2242 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2243 2244 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2245 2246 Example using 2 processes: 2247 $ NX (number of points on dm): 4 2248 $ sectionA : the on-disk section 2249 $ vecA : a vector associated with sectionA 2250 $ sectionB : sectiondm's local section constructed in this function 2251 $ vecB (local) : a vector associated with sectiondm's local section 2252 $ vecB (global) : a vector associated with sectiondm's global section 2253 $ 2254 $ rank 0 rank 1 2255 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2256 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2257 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2258 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2259 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2260 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2261 $ sectionB->atlasDof : 1 0 1 | 1 3 2262 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2263 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2264 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2265 $ 2266 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2267 2268 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2269 @*/ 2270 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2279 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2280 if (localDofSF) PetscValidPointer(localDofSF, 6); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2296 2297 Collective on DM 2298 2299 Input Parameters: 2300 + dm - The DM that represents the topology 2301 . viewer - The PetscViewer that represents the on-disk vector data 2302 . sectiondm - The DM that contains the global section on which vec is defined 2303 . sf - The SF that migrates the on-disk vector data into vec 2304 - vec - The global vector to set values of 2305 2306 Level: advanced 2307 2308 Notes: 2309 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2310 2311 Typical calling sequence 2312 $ DMCreate(PETSC_COMM_WORLD, &dm); 2313 $ DMSetType(dm, DMPLEX); 2314 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2316 $ DMClone(dm, §iondm); 2317 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2319 $ DMGetGlobalVector(sectiondm, &vec); 2320 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2322 $ DMRestoreGlobalVector(sectiondm, &vec); 2323 $ PetscSFDestroy(&gsf); 2324 $ PetscSFDestroy(&sfX); 2325 $ DMDestroy(§iondm); 2326 $ DMDestroy(&dm); 2327 2328 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2329 @*/ 2330 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2331 { 2332 PetscBool ishdf5; 2333 2334 PetscFunctionBegin; 2335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2336 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2337 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2338 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2339 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2340 /* Check consistency */ 2341 { 2342 PetscSection section; 2343 PetscBool includesConstraints; 2344 PetscInt m, m1; 2345 2346 PetscCall(VecGetLocalSize(vec, &m1)); 2347 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2348 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2349 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2350 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2351 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2352 } 2353 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2354 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2355 if (ishdf5) { 2356 #if defined(PETSC_HAVE_HDF5) 2357 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2358 #else 2359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2360 #endif 2361 } 2362 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2368 2369 Collective on DM 2370 2371 Input Parameters: 2372 + dm - The DM that represents the topology 2373 . viewer - The PetscViewer that represents the on-disk vector data 2374 . sectiondm - The DM that contains the local section on which vec is defined 2375 . sf - The SF that migrates the on-disk vector data into vec 2376 - vec - The local vector to set values of 2377 2378 Level: advanced 2379 2380 Notes: 2381 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Typical calling sequence 2384 $ DMCreate(PETSC_COMM_WORLD, &dm); 2385 $ DMSetType(dm, DMPLEX); 2386 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2387 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2388 $ DMClone(dm, §iondm); 2389 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2391 $ DMGetLocalVector(sectiondm, &vec); 2392 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2393 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2394 $ DMRestoreLocalVector(sectiondm, &vec); 2395 $ PetscSFDestroy(&lsf); 2396 $ PetscSFDestroy(&sfX); 2397 $ DMDestroy(§iondm); 2398 $ DMDestroy(&dm); 2399 2400 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2401 @*/ 2402 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2403 { 2404 PetscBool ishdf5; 2405 2406 PetscFunctionBegin; 2407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2408 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2409 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2410 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2411 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2412 /* Check consistency */ 2413 { 2414 PetscSection section; 2415 PetscBool includesConstraints; 2416 PetscInt m, m1; 2417 2418 PetscCall(VecGetLocalSize(vec, &m1)); 2419 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2420 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2421 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2422 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2423 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2424 } 2425 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2426 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2427 if (ishdf5) { 2428 #if defined(PETSC_HAVE_HDF5) 2429 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2435 PetscFunctionReturn(0); 2436 } 2437 2438 PetscErrorCode DMDestroy_Plex(DM dm) 2439 { 2440 DM_Plex *mesh = (DM_Plex*) dm->data; 2441 2442 PetscFunctionBegin; 2443 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2444 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2445 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2446 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2452 if (--mesh->refct > 0) PetscFunctionReturn(0); 2453 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2454 PetscCall(PetscFree(mesh->cones)); 2455 PetscCall(PetscFree(mesh->coneOrientations)); 2456 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2457 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2458 PetscCall(PetscFree(mesh->supports)); 2459 PetscCall(PetscFree(mesh->facesTmp)); 2460 PetscCall(PetscFree(mesh->tetgenOpts)); 2461 PetscCall(PetscFree(mesh->triangleOpts)); 2462 PetscCall(PetscFree(mesh->transformType)); 2463 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2464 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2465 PetscCall(ISDestroy(&mesh->subpointIS)); 2466 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2467 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2468 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2469 PetscCall(ISDestroy(&mesh->anchorIS)); 2470 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2471 PetscCall(PetscFree(mesh->parents)); 2472 PetscCall(PetscFree(mesh->childIDs)); 2473 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2474 PetscCall(PetscFree(mesh->children)); 2475 PetscCall(DMDestroy(&mesh->referenceTree)); 2476 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2477 PetscCall(PetscFree(mesh->neighbors)); 2478 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2479 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2480 PetscCall(PetscFree(mesh)); 2481 PetscFunctionReturn(0); 2482 } 2483 2484 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2485 { 2486 PetscSection sectionGlobal; 2487 PetscInt bs = -1, mbs; 2488 PetscInt localSize, localStart = 0; 2489 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2490 MatType mtype; 2491 ISLocalToGlobalMapping ltog; 2492 2493 PetscFunctionBegin; 2494 PetscCall(MatInitializePackage()); 2495 mtype = dm->mattype; 2496 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2497 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2498 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2499 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm))); 2500 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2501 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2502 PetscCall(MatSetType(*J, mtype)); 2503 PetscCall(MatSetFromOptions(*J)); 2504 PetscCall(MatGetBlockSize(*J, &mbs)); 2505 if (mbs > 1) bs = mbs; 2506 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2507 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2508 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2509 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2510 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2511 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2512 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2513 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2514 if (!isShell) { 2515 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2516 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2517 PetscInt pStart, pEnd, p, dof, cdof; 2518 2519 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2520 2521 PetscCall(PetscCalloc1(localSize, &pblocks)); 2522 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2523 for (p = pStart; p < pEnd; ++p) { 2524 PetscInt bdof, offset; 2525 2526 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2527 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2528 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2529 for (PetscInt i=0; i < dof - cdof; i++) 2530 pblocks[offset - localStart + i] = dof - cdof; 2531 dof = dof < 0 ? -(dof+1) : dof; 2532 bdof = cdof && (dof-cdof) ? 1 : dof; 2533 if (dof) { 2534 if (bs < 0) {bs = bdof;} 2535 else if (bs != bdof) {bs = 1;} 2536 } 2537 } 2538 /* Must have same blocksize on all procs (some might have no points) */ 2539 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2540 bsLocal[1] = bs; 2541 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2542 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2543 else bs = bsMinMax[0]; 2544 bs = PetscMax(1,bs); 2545 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2546 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2547 PetscCall(MatSetBlockSize(*J, bs)); 2548 PetscCall(MatSetUp(*J)); 2549 } else { 2550 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2551 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2552 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2553 } 2554 { // Consolidate blocks 2555 PetscInt nblocks = 0; 2556 for (PetscInt i=0; i<localSize; i += PetscMax(1, pblocks[i])) { 2557 if (pblocks[i] == 0) continue; 2558 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2559 for (PetscInt j=1; j<pblocks[i]; j++) { 2560 PetscCheck(pblocks[i+j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i+j]); 2561 } 2562 } 2563 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2564 } 2565 PetscCall(PetscFree(pblocks)); 2566 } 2567 PetscCall(MatSetDM(*J, dm)); 2568 PetscFunctionReturn(0); 2569 } 2570 2571 /*@ 2572 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2573 2574 Not collective 2575 2576 Input Parameter: 2577 . mesh - The DMPlex 2578 2579 Output Parameters: 2580 . subsection - The subdomain section 2581 2582 Level: developer 2583 2584 .seealso: 2585 @*/ 2586 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2587 { 2588 DM_Plex *mesh = (DM_Plex*) dm->data; 2589 2590 PetscFunctionBegin; 2591 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2592 if (!mesh->subdomainSection) { 2593 PetscSection section; 2594 PetscSF sf; 2595 2596 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2597 PetscCall(DMGetLocalSection(dm,§ion)); 2598 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2599 PetscCall(PetscSFDestroy(&sf)); 2600 } 2601 *subsection = mesh->subdomainSection; 2602 PetscFunctionReturn(0); 2603 } 2604 2605 /*@ 2606 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2607 2608 Not collective 2609 2610 Input Parameter: 2611 . mesh - The DMPlex 2612 2613 Output Parameters: 2614 + pStart - The first mesh point 2615 - pEnd - The upper bound for mesh points 2616 2617 Level: beginner 2618 2619 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2620 @*/ 2621 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2622 { 2623 DM_Plex *mesh = (DM_Plex*) dm->data; 2624 2625 PetscFunctionBegin; 2626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2627 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2628 PetscFunctionReturn(0); 2629 } 2630 2631 /*@ 2632 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2633 2634 Not collective 2635 2636 Input Parameters: 2637 + mesh - The DMPlex 2638 . pStart - The first mesh point 2639 - pEnd - The upper bound for mesh points 2640 2641 Output Parameters: 2642 2643 Level: beginner 2644 2645 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2646 @*/ 2647 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2648 { 2649 DM_Plex *mesh = (DM_Plex*) dm->data; 2650 2651 PetscFunctionBegin; 2652 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2653 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2654 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2655 PetscFunctionReturn(0); 2656 } 2657 2658 /*@ 2659 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2660 2661 Not collective 2662 2663 Input Parameters: 2664 + mesh - The DMPlex 2665 - p - The point, which must lie in the chart set with DMPlexSetChart() 2666 2667 Output Parameter: 2668 . size - The cone size for point p 2669 2670 Level: beginner 2671 2672 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2673 @*/ 2674 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2675 { 2676 DM_Plex *mesh = (DM_Plex*) dm->data; 2677 2678 PetscFunctionBegin; 2679 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2680 PetscValidIntPointer(size, 3); 2681 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2682 PetscFunctionReturn(0); 2683 } 2684 2685 /*@ 2686 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2687 2688 Not collective 2689 2690 Input Parameters: 2691 + mesh - The DMPlex 2692 . p - The point, which must lie in the chart set with DMPlexSetChart() 2693 - size - The cone size for point p 2694 2695 Output Parameter: 2696 2697 Note: 2698 This should be called after DMPlexSetChart(). 2699 2700 Level: beginner 2701 2702 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2703 @*/ 2704 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2705 { 2706 DM_Plex *mesh = (DM_Plex*) dm->data; 2707 2708 PetscFunctionBegin; 2709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2710 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2711 PetscFunctionReturn(0); 2712 } 2713 2714 /*@ 2715 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2716 2717 Not collective 2718 2719 Input Parameters: 2720 + mesh - The DMPlex 2721 . p - The point, which must lie in the chart set with DMPlexSetChart() 2722 - size - The additional cone size for point p 2723 2724 Output Parameter: 2725 2726 Note: 2727 This should be called after DMPlexSetChart(). 2728 2729 Level: beginner 2730 2731 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2732 @*/ 2733 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2734 { 2735 DM_Plex *mesh = (DM_Plex*) dm->data; 2736 PetscFunctionBegin; 2737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2738 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2739 PetscFunctionReturn(0); 2740 } 2741 2742 /*@C 2743 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2744 2745 Not collective 2746 2747 Input Parameters: 2748 + dm - The DMPlex 2749 - p - The point, which must lie in the chart set with DMPlexSetChart() 2750 2751 Output Parameter: 2752 . cone - An array of points which are on the in-edges for point p 2753 2754 Level: beginner 2755 2756 Fortran Notes: 2757 Since it returns an array, this routine is only available in Fortran 90, and you must 2758 include petsc.h90 in your code. 2759 You must also call DMPlexRestoreCone() after you finish using the returned array. 2760 DMPlexRestoreCone() is not needed/available in C. 2761 2762 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2763 @*/ 2764 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2765 { 2766 DM_Plex *mesh = (DM_Plex*) dm->data; 2767 PetscInt off; 2768 2769 PetscFunctionBegin; 2770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2771 PetscValidPointer(cone, 3); 2772 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2773 *cone = &mesh->cones[off]; 2774 PetscFunctionReturn(0); 2775 } 2776 2777 /*@C 2778 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2779 2780 Not collective 2781 2782 Input Parameters: 2783 + dm - The DMPlex 2784 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2785 2786 Output Parameters: 2787 + pConesSection - PetscSection describing the layout of pCones 2788 - pCones - An array of points which are on the in-edges for the point set p 2789 2790 Level: intermediate 2791 2792 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2793 @*/ 2794 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2795 { 2796 PetscSection cs, newcs; 2797 PetscInt *cones; 2798 PetscInt *newarr=NULL; 2799 PetscInt n; 2800 2801 PetscFunctionBegin; 2802 PetscCall(DMPlexGetCones(dm, &cones)); 2803 PetscCall(DMPlexGetConeSection(dm, &cs)); 2804 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2805 if (pConesSection) *pConesSection = newcs; 2806 if (pCones) { 2807 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2808 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2809 } 2810 PetscFunctionReturn(0); 2811 } 2812 2813 /*@ 2814 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2815 2816 Not collective 2817 2818 Input Parameters: 2819 + dm - The DMPlex 2820 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2821 2822 Output Parameter: 2823 . expandedPoints - An array of vertices recursively expanded from input points 2824 2825 Level: advanced 2826 2827 Notes: 2828 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2829 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2830 2831 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2832 @*/ 2833 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2834 { 2835 IS *expandedPointsAll; 2836 PetscInt depth; 2837 2838 PetscFunctionBegin; 2839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2840 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2841 PetscValidPointer(expandedPoints, 3); 2842 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2843 *expandedPoints = expandedPointsAll[0]; 2844 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2845 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2846 PetscFunctionReturn(0); 2847 } 2848 2849 /*@ 2850 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). 2851 2852 Not collective 2853 2854 Input Parameters: 2855 + dm - The DMPlex 2856 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2857 2858 Output Parameters: 2859 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2860 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2861 - sections - (optional) An array of sections which describe mappings from points to their cone points 2862 2863 Level: advanced 2864 2865 Notes: 2866 Like DMPlexGetConeTuple() but recursive. 2867 2868 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. 2869 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2870 2871 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: 2872 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2873 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2874 2875 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2876 @*/ 2877 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2878 { 2879 const PetscInt *arr0=NULL, *cone=NULL; 2880 PetscInt *arr=NULL, *newarr=NULL; 2881 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2882 IS *expandedPoints_; 2883 PetscSection *sections_; 2884 2885 PetscFunctionBegin; 2886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2887 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2888 if (depth) PetscValidIntPointer(depth, 3); 2889 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2890 if (sections) PetscValidPointer(sections, 5); 2891 PetscCall(ISGetLocalSize(points, &n)); 2892 PetscCall(ISGetIndices(points, &arr0)); 2893 PetscCall(DMPlexGetDepth(dm, &depth_)); 2894 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2895 PetscCall(PetscCalloc1(depth_, §ions_)); 2896 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2897 for (d=depth_-1; d>=0; d--) { 2898 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2899 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2900 for (i=0; i<n; i++) { 2901 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2902 if (arr[i] >= start && arr[i] < end) { 2903 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2904 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2905 } else { 2906 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2907 } 2908 } 2909 PetscCall(PetscSectionSetUp(sections_[d])); 2910 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2911 PetscCall(PetscMalloc1(newn, &newarr)); 2912 for (i=0; i<n; i++) { 2913 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2914 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2915 if (cn > 1) { 2916 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2917 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2918 } else { 2919 newarr[co] = arr[i]; 2920 } 2921 } 2922 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2923 arr = newarr; 2924 n = newn; 2925 } 2926 PetscCall(ISRestoreIndices(points, &arr0)); 2927 *depth = depth_; 2928 if (expandedPoints) *expandedPoints = expandedPoints_; 2929 else { 2930 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2931 PetscCall(PetscFree(expandedPoints_)); 2932 } 2933 if (sections) *sections = sections_; 2934 else { 2935 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2936 PetscCall(PetscFree(sections_)); 2937 } 2938 PetscFunctionReturn(0); 2939 } 2940 2941 /*@ 2942 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2943 2944 Not collective 2945 2946 Input Parameters: 2947 + dm - The DMPlex 2948 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2949 2950 Output Parameters: 2951 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2952 . expandedPoints - (optional) An array of recursively expanded cones 2953 - sections - (optional) An array of sections which describe mappings from points to their cone points 2954 2955 Level: advanced 2956 2957 Notes: 2958 See DMPlexGetConeRecursive() for details. 2959 2960 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2961 @*/ 2962 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2963 { 2964 PetscInt d, depth_; 2965 2966 PetscFunctionBegin; 2967 PetscCall(DMPlexGetDepth(dm, &depth_)); 2968 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2969 if (depth) *depth = 0; 2970 if (expandedPoints) { 2971 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2972 PetscCall(PetscFree(*expandedPoints)); 2973 } 2974 if (sections) { 2975 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2976 PetscCall(PetscFree(*sections)); 2977 } 2978 PetscFunctionReturn(0); 2979 } 2980 2981 /*@ 2982 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 2983 2984 Not collective 2985 2986 Input Parameters: 2987 + mesh - The DMPlex 2988 . p - The point, which must lie in the chart set with DMPlexSetChart() 2989 - cone - An array of points which are on the in-edges for point p 2990 2991 Output Parameter: 2992 2993 Note: 2994 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2995 2996 Level: beginner 2997 2998 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2999 @*/ 3000 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3001 { 3002 DM_Plex *mesh = (DM_Plex*) dm->data; 3003 PetscInt pStart, pEnd; 3004 PetscInt dof, off, c; 3005 3006 PetscFunctionBegin; 3007 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3008 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3009 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3010 if (dof) PetscValidIntPointer(cone, 3); 3011 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3012 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3013 for (c = 0; c < dof; ++c) { 3014 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3015 mesh->cones[off+c] = cone[c]; 3016 } 3017 PetscFunctionReturn(0); 3018 } 3019 3020 /*@C 3021 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3022 3023 Not collective 3024 3025 Input Parameters: 3026 + mesh - The DMPlex 3027 - p - The point, which must lie in the chart set with DMPlexSetChart() 3028 3029 Output Parameter: 3030 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3031 integer giving the prescription for cone traversal. 3032 3033 Level: beginner 3034 3035 Notes: 3036 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3037 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3038 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3039 with the identity. 3040 3041 Fortran Notes: 3042 Since it returns an array, this routine is only available in Fortran 90, and you must 3043 include petsc.h90 in your code. 3044 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3045 DMPlexRestoreConeOrientation() is not needed/available in C. 3046 3047 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3048 @*/ 3049 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3050 { 3051 DM_Plex *mesh = (DM_Plex*) dm->data; 3052 PetscInt off; 3053 3054 PetscFunctionBegin; 3055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3056 if (PetscDefined(USE_DEBUG)) { 3057 PetscInt dof; 3058 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3059 if (dof) PetscValidPointer(coneOrientation, 3); 3060 } 3061 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3062 3063 *coneOrientation = &mesh->coneOrientations[off]; 3064 PetscFunctionReturn(0); 3065 } 3066 3067 /*@ 3068 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3069 3070 Not collective 3071 3072 Input Parameters: 3073 + mesh - The DMPlex 3074 . p - The point, which must lie in the chart set with DMPlexSetChart() 3075 - coneOrientation - An array of orientations 3076 Output Parameter: 3077 3078 Notes: 3079 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3080 3081 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3082 3083 Level: beginner 3084 3085 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3086 @*/ 3087 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3088 { 3089 DM_Plex *mesh = (DM_Plex*) dm->data; 3090 PetscInt pStart, pEnd; 3091 PetscInt dof, off, c; 3092 3093 PetscFunctionBegin; 3094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3095 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3096 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3097 if (dof) PetscValidIntPointer(coneOrientation, 3); 3098 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3099 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3100 for (c = 0; c < dof; ++c) { 3101 PetscInt cdof, o = coneOrientation[c]; 3102 3103 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3104 PetscCheck(!o || (o >= -(cdof+1) && o < cdof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof+1), cdof); 3105 mesh->coneOrientations[off+c] = o; 3106 } 3107 PetscFunctionReturn(0); 3108 } 3109 3110 /*@ 3111 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3112 3113 Not collective 3114 3115 Input Parameters: 3116 + mesh - The DMPlex 3117 . p - The point, which must lie in the chart set with DMPlexSetChart() 3118 . conePos - The local index in the cone where the point should be put 3119 - conePoint - The mesh point to insert 3120 3121 Level: beginner 3122 3123 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3124 @*/ 3125 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3126 { 3127 DM_Plex *mesh = (DM_Plex*) dm->data; 3128 PetscInt pStart, pEnd; 3129 PetscInt dof, off; 3130 3131 PetscFunctionBegin; 3132 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3133 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3134 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3135 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3136 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3137 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3138 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3139 mesh->cones[off+conePos] = conePoint; 3140 PetscFunctionReturn(0); 3141 } 3142 3143 /*@ 3144 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3145 3146 Not collective 3147 3148 Input Parameters: 3149 + mesh - The DMPlex 3150 . p - The point, which must lie in the chart set with DMPlexSetChart() 3151 . conePos - The local index in the cone where the point should be put 3152 - coneOrientation - The point orientation to insert 3153 3154 Level: beginner 3155 3156 Notes: 3157 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3158 3159 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3160 @*/ 3161 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3162 { 3163 DM_Plex *mesh = (DM_Plex*) dm->data; 3164 PetscInt pStart, pEnd; 3165 PetscInt dof, off; 3166 3167 PetscFunctionBegin; 3168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3169 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3170 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3171 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3172 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3173 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3174 mesh->coneOrientations[off+conePos] = coneOrientation; 3175 PetscFunctionReturn(0); 3176 } 3177 3178 /*@ 3179 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3180 3181 Not collective 3182 3183 Input Parameters: 3184 + mesh - The DMPlex 3185 - p - The point, which must lie in the chart set with DMPlexSetChart() 3186 3187 Output Parameter: 3188 . size - The support size for point p 3189 3190 Level: beginner 3191 3192 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3193 @*/ 3194 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3195 { 3196 DM_Plex *mesh = (DM_Plex*) dm->data; 3197 3198 PetscFunctionBegin; 3199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3200 PetscValidIntPointer(size, 3); 3201 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3202 PetscFunctionReturn(0); 3203 } 3204 3205 /*@ 3206 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3207 3208 Not collective 3209 3210 Input Parameters: 3211 + mesh - The DMPlex 3212 . p - The point, which must lie in the chart set with DMPlexSetChart() 3213 - size - The support size for point p 3214 3215 Output Parameter: 3216 3217 Note: 3218 This should be called after DMPlexSetChart(). 3219 3220 Level: beginner 3221 3222 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3223 @*/ 3224 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3225 { 3226 DM_Plex *mesh = (DM_Plex*) dm->data; 3227 3228 PetscFunctionBegin; 3229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3230 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3231 PetscFunctionReturn(0); 3232 } 3233 3234 /*@C 3235 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3236 3237 Not collective 3238 3239 Input Parameters: 3240 + mesh - The DMPlex 3241 - p - The point, which must lie in the chart set with DMPlexSetChart() 3242 3243 Output Parameter: 3244 . support - An array of points which are on the out-edges for point p 3245 3246 Level: beginner 3247 3248 Fortran Notes: 3249 Since it returns an array, this routine is only available in Fortran 90, and you must 3250 include petsc.h90 in your code. 3251 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3252 DMPlexRestoreSupport() is not needed/available in C. 3253 3254 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3255 @*/ 3256 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3257 { 3258 DM_Plex *mesh = (DM_Plex*) dm->data; 3259 PetscInt off; 3260 3261 PetscFunctionBegin; 3262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3263 PetscValidPointer(support, 3); 3264 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3265 *support = &mesh->supports[off]; 3266 PetscFunctionReturn(0); 3267 } 3268 3269 /*@ 3270 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3271 3272 Not collective 3273 3274 Input Parameters: 3275 + mesh - The DMPlex 3276 . p - The point, which must lie in the chart set with DMPlexSetChart() 3277 - support - An array of points which are on the out-edges for point p 3278 3279 Output Parameter: 3280 3281 Note: 3282 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3283 3284 Level: beginner 3285 3286 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3287 @*/ 3288 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3289 { 3290 DM_Plex *mesh = (DM_Plex*) dm->data; 3291 PetscInt pStart, pEnd; 3292 PetscInt dof, off, c; 3293 3294 PetscFunctionBegin; 3295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3296 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3297 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3298 if (dof) PetscValidIntPointer(support, 3); 3299 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3300 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3301 for (c = 0; c < dof; ++c) { 3302 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3303 mesh->supports[off+c] = support[c]; 3304 } 3305 PetscFunctionReturn(0); 3306 } 3307 3308 /*@ 3309 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3310 3311 Not collective 3312 3313 Input Parameters: 3314 + mesh - The DMPlex 3315 . p - The point, which must lie in the chart set with DMPlexSetChart() 3316 . supportPos - The local index in the cone where the point should be put 3317 - supportPoint - The mesh point to insert 3318 3319 Level: beginner 3320 3321 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3322 @*/ 3323 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3324 { 3325 DM_Plex *mesh = (DM_Plex*) dm->data; 3326 PetscInt pStart, pEnd; 3327 PetscInt dof, off; 3328 3329 PetscFunctionBegin; 3330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3331 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3332 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3333 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3334 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3335 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3336 PetscCheck(supportPos < dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3337 mesh->supports[off+supportPos] = supportPoint; 3338 PetscFunctionReturn(0); 3339 } 3340 3341 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3342 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3343 { 3344 switch (ct) { 3345 case DM_POLYTOPE_SEGMENT: 3346 if (o == -1) return -2; 3347 break; 3348 case DM_POLYTOPE_TRIANGLE: 3349 if (o == -3) return -1; 3350 if (o == -2) return -3; 3351 if (o == -1) return -2; 3352 break; 3353 case DM_POLYTOPE_QUADRILATERAL: 3354 if (o == -4) return -2; 3355 if (o == -3) return -1; 3356 if (o == -2) return -4; 3357 if (o == -1) return -3; 3358 break; 3359 default: return o; 3360 } 3361 return o; 3362 } 3363 3364 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3365 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3366 { 3367 switch (ct) { 3368 case DM_POLYTOPE_SEGMENT: 3369 if ((o == -2) || (o == 1)) return -1; 3370 if (o == -1) return 0; 3371 break; 3372 case DM_POLYTOPE_TRIANGLE: 3373 if (o == -3) return -2; 3374 if (o == -2) return -1; 3375 if (o == -1) return -3; 3376 break; 3377 case DM_POLYTOPE_QUADRILATERAL: 3378 if (o == -4) return -2; 3379 if (o == -3) return -1; 3380 if (o == -2) return -4; 3381 if (o == -1) return -3; 3382 break; 3383 default: return o; 3384 } 3385 return o; 3386 } 3387 3388 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3389 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3390 { 3391 PetscInt pStart, pEnd, p; 3392 3393 PetscFunctionBegin; 3394 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3395 for (p = pStart; p < pEnd; ++p) { 3396 const PetscInt *cone, *ornt; 3397 PetscInt coneSize, c; 3398 3399 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3400 PetscCall(DMPlexGetCone(dm, p, &cone)); 3401 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3402 for (c = 0; c < coneSize; ++c) { 3403 DMPolytopeType ct; 3404 const PetscInt o = ornt[c]; 3405 3406 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3407 switch (ct) { 3408 case DM_POLYTOPE_SEGMENT: 3409 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3410 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3411 break; 3412 case DM_POLYTOPE_TRIANGLE: 3413 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3414 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3415 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3416 break; 3417 case DM_POLYTOPE_QUADRILATERAL: 3418 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3419 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3420 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3421 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3422 break; 3423 default: break; 3424 } 3425 } 3426 } 3427 PetscFunctionReturn(0); 3428 } 3429 3430 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3431 { 3432 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3433 PetscInt *closure; 3434 const PetscInt *tmp = NULL, *tmpO = NULL; 3435 PetscInt off = 0, tmpSize, t; 3436 3437 PetscFunctionBeginHot; 3438 if (ornt) { 3439 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3440 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3441 } 3442 if (*points) { 3443 closure = *points; 3444 } else { 3445 PetscInt maxConeSize, maxSupportSize; 3446 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3447 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3448 } 3449 if (useCone) { 3450 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3451 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3452 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3453 } else { 3454 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3455 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3456 } 3457 if (ct == DM_POLYTOPE_UNKNOWN) { 3458 closure[off++] = p; 3459 closure[off++] = 0; 3460 for (t = 0; t < tmpSize; ++t) { 3461 closure[off++] = tmp[t]; 3462 closure[off++] = tmpO ? tmpO[t] : 0; 3463 } 3464 } else { 3465 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3466 3467 /* We assume that cells with a valid type have faces with a valid type */ 3468 closure[off++] = p; 3469 closure[off++] = ornt; 3470 for (t = 0; t < tmpSize; ++t) { 3471 DMPolytopeType ft; 3472 3473 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3474 closure[off++] = tmp[arr[t]]; 3475 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3476 } 3477 } 3478 if (numPoints) *numPoints = tmpSize+1; 3479 if (points) *points = closure; 3480 PetscFunctionReturn(0); 3481 } 3482 3483 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3484 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3485 { 3486 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3487 const PetscInt *cone, *ornt; 3488 PetscInt *pts, *closure = NULL; 3489 DMPolytopeType ft; 3490 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3491 PetscInt dim, coneSize, c, d, clSize, cl; 3492 3493 PetscFunctionBeginHot; 3494 PetscCall(DMGetDimension(dm, &dim)); 3495 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3496 PetscCall(DMPlexGetCone(dm, point, &cone)); 3497 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3498 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3499 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3500 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3501 maxSize = PetscMax(coneSeries, supportSeries); 3502 if (*points) {pts = *points;} 3503 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3504 c = 0; 3505 pts[c++] = point; 3506 pts[c++] = o; 3507 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3508 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3509 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3510 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3511 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3512 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3513 for (d = 2; d < coneSize; ++d) { 3514 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3515 pts[c++] = cone[arr[d*2+0]]; 3516 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3517 } 3518 if (dim >= 3) { 3519 for (d = 2; d < coneSize; ++d) { 3520 const PetscInt fpoint = cone[arr[d*2+0]]; 3521 const PetscInt *fcone, *fornt; 3522 PetscInt fconeSize, fc, i; 3523 3524 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3525 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3526 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3527 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3528 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3529 for (fc = 0; fc < fconeSize; ++fc) { 3530 const PetscInt cp = fcone[farr[fc*2+0]]; 3531 const PetscInt co = farr[fc*2+1]; 3532 3533 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3534 if (i == c) { 3535 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3536 pts[c++] = cp; 3537 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3538 } 3539 } 3540 } 3541 } 3542 *numPoints = c/2; 3543 *points = pts; 3544 PetscFunctionReturn(0); 3545 } 3546 3547 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3548 { 3549 DMPolytopeType ct; 3550 PetscInt *closure, *fifo; 3551 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3552 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3553 PetscInt depth, maxSize; 3554 3555 PetscFunctionBeginHot; 3556 PetscCall(DMPlexGetDepth(dm, &depth)); 3557 if (depth == 1) { 3558 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3559 PetscFunctionReturn(0); 3560 } 3561 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3562 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3563 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3564 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3565 PetscFunctionReturn(0); 3566 } 3567 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3568 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3569 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3570 maxSize = PetscMax(coneSeries, supportSeries); 3571 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3572 if (*points) {closure = *points;} 3573 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3574 closure[closureSize++] = p; 3575 closure[closureSize++] = ornt; 3576 fifo[fifoSize++] = p; 3577 fifo[fifoSize++] = ornt; 3578 fifo[fifoSize++] = ct; 3579 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3580 while (fifoSize - fifoStart) { 3581 const PetscInt q = fifo[fifoStart++]; 3582 const PetscInt o = fifo[fifoStart++]; 3583 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3584 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3585 const PetscInt *tmp, *tmpO; 3586 PetscInt tmpSize, t; 3587 3588 if (PetscDefined(USE_DEBUG)) { 3589 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3590 PetscCheck(!o || !(o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3591 } 3592 if (useCone) { 3593 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3594 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3595 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3596 } else { 3597 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3598 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3599 tmpO = NULL; 3600 } 3601 for (t = 0; t < tmpSize; ++t) { 3602 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3603 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3604 const PetscInt cp = tmp[ip]; 3605 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3606 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3607 PetscInt c; 3608 3609 /* Check for duplicate */ 3610 for (c = 0; c < closureSize; c += 2) { 3611 if (closure[c] == cp) break; 3612 } 3613 if (c == closureSize) { 3614 closure[closureSize++] = cp; 3615 closure[closureSize++] = co; 3616 fifo[fifoSize++] = cp; 3617 fifo[fifoSize++] = co; 3618 fifo[fifoSize++] = ct; 3619 } 3620 } 3621 } 3622 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3623 if (numPoints) *numPoints = closureSize/2; 3624 if (points) *points = closure; 3625 PetscFunctionReturn(0); 3626 } 3627 3628 /*@C 3629 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3630 3631 Not collective 3632 3633 Input Parameters: 3634 + dm - The DMPlex 3635 . p - The mesh point 3636 - useCone - PETSC_TRUE for the closure, otherwise return the star 3637 3638 Input/Output Parameter: 3639 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3640 if NULL on input, internal storage will be returned, otherwise the provided array is used 3641 3642 Output Parameter: 3643 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3644 3645 Note: 3646 If using internal storage (points is NULL on input), each call overwrites the last output. 3647 3648 Fortran Notes: 3649 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3650 3651 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3652 3653 Level: beginner 3654 3655 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3656 @*/ 3657 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3658 { 3659 PetscFunctionBeginHot; 3660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3661 if (numPoints) PetscValidIntPointer(numPoints, 4); 3662 if (points) PetscValidPointer(points, 5); 3663 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3664 PetscFunctionReturn(0); 3665 } 3666 3667 /*@C 3668 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3669 3670 Not collective 3671 3672 Input Parameters: 3673 + dm - The DMPlex 3674 . p - The mesh point 3675 . useCone - PETSC_TRUE for the closure, otherwise return the star 3676 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3677 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3678 3679 Note: 3680 If not using internal storage (points is not NULL on input), this call is unnecessary 3681 3682 Fortran Notes: 3683 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3684 3685 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3686 3687 Level: beginner 3688 3689 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3690 @*/ 3691 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3692 { 3693 PetscFunctionBeginHot; 3694 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3695 if (numPoints) *numPoints = 0; 3696 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3697 PetscFunctionReturn(0); 3698 } 3699 3700 /*@ 3701 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3702 3703 Not collective 3704 3705 Input Parameter: 3706 . mesh - The DMPlex 3707 3708 Output Parameters: 3709 + maxConeSize - The maximum number of in-edges 3710 - maxSupportSize - The maximum number of out-edges 3711 3712 Level: beginner 3713 3714 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3715 @*/ 3716 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3717 { 3718 DM_Plex *mesh = (DM_Plex*) dm->data; 3719 3720 PetscFunctionBegin; 3721 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3722 if (maxConeSize) { 3723 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3724 } 3725 if (maxSupportSize) { 3726 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3727 } 3728 PetscFunctionReturn(0); 3729 } 3730 3731 PetscErrorCode DMSetUp_Plex(DM dm) 3732 { 3733 DM_Plex *mesh = (DM_Plex*) dm->data; 3734 PetscInt size, maxSupportSize; 3735 3736 PetscFunctionBegin; 3737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3738 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3739 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3740 PetscCall(PetscMalloc1(size, &mesh->cones)); 3741 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3742 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3743 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3744 if (maxSupportSize) { 3745 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3746 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3747 PetscCall(PetscMalloc1(size, &mesh->supports)); 3748 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3749 } 3750 PetscFunctionReturn(0); 3751 } 3752 3753 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3754 { 3755 PetscFunctionBegin; 3756 if (subdm) PetscCall(DMClone(dm, subdm)); 3757 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3758 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3759 if (dm->useNatural && dm->sfMigration) { 3760 PetscSF sfMigrationInv,sfNatural; 3761 PetscSection section, sectionSeq; 3762 3763 (*subdm)->sfMigration = dm->sfMigration; 3764 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3765 PetscCall(DMGetLocalSection((*subdm), §ion)); 3766 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3767 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3768 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3769 3770 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3771 (*subdm)->sfNatural = sfNatural; 3772 PetscCall(PetscSectionDestroy(§ionSeq)); 3773 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3774 } 3775 PetscFunctionReturn(0); 3776 } 3777 3778 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3779 { 3780 PetscInt i = 0; 3781 3782 PetscFunctionBegin; 3783 PetscCall(DMClone(dms[0], superdm)); 3784 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3785 (*superdm)->useNatural = PETSC_FALSE; 3786 for (i = 0; i < len; i++) { 3787 if (dms[i]->useNatural && dms[i]->sfMigration) { 3788 PetscSF sfMigrationInv,sfNatural; 3789 PetscSection section, sectionSeq; 3790 3791 (*superdm)->sfMigration = dms[i]->sfMigration; 3792 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3793 (*superdm)->useNatural = PETSC_TRUE; 3794 PetscCall(DMGetLocalSection((*superdm), §ion)); 3795 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3796 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3797 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3798 3799 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3800 (*superdm)->sfNatural = sfNatural; 3801 PetscCall(PetscSectionDestroy(§ionSeq)); 3802 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3803 break; 3804 } 3805 } 3806 PetscFunctionReturn(0); 3807 } 3808 3809 /*@ 3810 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3811 3812 Not collective 3813 3814 Input Parameter: 3815 . mesh - The DMPlex 3816 3817 Output Parameter: 3818 3819 Note: 3820 This should be called after all calls to DMPlexSetCone() 3821 3822 Level: beginner 3823 3824 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3825 @*/ 3826 PetscErrorCode DMPlexSymmetrize(DM dm) 3827 { 3828 DM_Plex *mesh = (DM_Plex*) dm->data; 3829 PetscInt *offsets; 3830 PetscInt supportSize; 3831 PetscInt pStart, pEnd, p; 3832 3833 PetscFunctionBegin; 3834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3835 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3836 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3837 /* Calculate support sizes */ 3838 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3839 for (p = pStart; p < pEnd; ++p) { 3840 PetscInt dof, off, c; 3841 3842 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3843 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3844 for (c = off; c < off+dof; ++c) { 3845 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3846 } 3847 } 3848 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3849 /* Calculate supports */ 3850 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3851 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3852 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3853 for (p = pStart; p < pEnd; ++p) { 3854 PetscInt dof, off, c; 3855 3856 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3857 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3858 for (c = off; c < off+dof; ++c) { 3859 const PetscInt q = mesh->cones[c]; 3860 PetscInt offS; 3861 3862 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3863 3864 mesh->supports[offS+offsets[q]] = p; 3865 ++offsets[q]; 3866 } 3867 } 3868 PetscCall(PetscFree(offsets)); 3869 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3870 PetscFunctionReturn(0); 3871 } 3872 3873 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3874 { 3875 IS stratumIS; 3876 3877 PetscFunctionBegin; 3878 if (pStart >= pEnd) PetscFunctionReturn(0); 3879 if (PetscDefined(USE_DEBUG)) { 3880 PetscInt qStart, qEnd, numLevels, level; 3881 PetscBool overlap = PETSC_FALSE; 3882 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3883 for (level = 0; level < numLevels; level++) { 3884 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3885 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3886 } 3887 PetscCheck(!overlap,PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 3888 } 3889 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3890 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3891 PetscCall(ISDestroy(&stratumIS)); 3892 PetscFunctionReturn(0); 3893 } 3894 3895 /*@ 3896 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3897 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3898 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3899 the DAG. 3900 3901 Collective on dm 3902 3903 Input Parameter: 3904 . mesh - The DMPlex 3905 3906 Output Parameter: 3907 3908 Notes: 3909 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3910 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3911 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3912 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3913 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3914 3915 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3916 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3917 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 3918 to interpolate only that one (e0), so that 3919 $ cone(c0) = {e0, v2} 3920 $ cone(e0) = {v0, v1} 3921 If DMPlexStratify() is run on this mesh, it will give depths 3922 $ depth 0 = {v0, v1, v2} 3923 $ depth 1 = {e0, c0} 3924 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3925 3926 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3927 3928 Level: beginner 3929 3930 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3931 @*/ 3932 PetscErrorCode DMPlexStratify(DM dm) 3933 { 3934 DM_Plex *mesh = (DM_Plex*) dm->data; 3935 DMLabel label; 3936 PetscInt pStart, pEnd, p; 3937 PetscInt numRoots = 0, numLeaves = 0; 3938 3939 PetscFunctionBegin; 3940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3941 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3942 3943 /* Create depth label */ 3944 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3945 PetscCall(DMCreateLabel(dm, "depth")); 3946 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3947 3948 { 3949 /* Initialize roots and count leaves */ 3950 PetscInt sMin = PETSC_MAX_INT; 3951 PetscInt sMax = PETSC_MIN_INT; 3952 PetscInt coneSize, supportSize; 3953 3954 for (p = pStart; p < pEnd; ++p) { 3955 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3956 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3957 if (!coneSize && supportSize) { 3958 sMin = PetscMin(p, sMin); 3959 sMax = PetscMax(p, sMax); 3960 ++numRoots; 3961 } else if (!supportSize && coneSize) { 3962 ++numLeaves; 3963 } else if (!supportSize && !coneSize) { 3964 /* Isolated points */ 3965 sMin = PetscMin(p, sMin); 3966 sMax = PetscMax(p, sMax); 3967 } 3968 } 3969 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3970 } 3971 3972 if (numRoots + numLeaves == (pEnd - pStart)) { 3973 PetscInt sMin = PETSC_MAX_INT; 3974 PetscInt sMax = PETSC_MIN_INT; 3975 PetscInt coneSize, supportSize; 3976 3977 for (p = pStart; p < pEnd; ++p) { 3978 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3979 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3980 if (!supportSize && coneSize) { 3981 sMin = PetscMin(p, sMin); 3982 sMax = PetscMax(p, sMax); 3983 } 3984 } 3985 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3986 } else { 3987 PetscInt level = 0; 3988 PetscInt qStart, qEnd, q; 3989 3990 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3991 while (qEnd > qStart) { 3992 PetscInt sMin = PETSC_MAX_INT; 3993 PetscInt sMax = PETSC_MIN_INT; 3994 3995 for (q = qStart; q < qEnd; ++q) { 3996 const PetscInt *support; 3997 PetscInt supportSize, s; 3998 3999 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4000 PetscCall(DMPlexGetSupport(dm, q, &support)); 4001 for (s = 0; s < supportSize; ++s) { 4002 sMin = PetscMin(support[s], sMin); 4003 sMax = PetscMax(support[s], sMax); 4004 } 4005 } 4006 PetscCall(DMLabelGetNumValues(label, &level)); 4007 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 4008 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4009 } 4010 } 4011 { /* just in case there is an empty process */ 4012 PetscInt numValues, maxValues = 0, v; 4013 4014 PetscCall(DMLabelGetNumValues(label, &numValues)); 4015 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4016 for (v = numValues; v < maxValues; v++) { 4017 PetscCall(DMLabelAddStratum(label, v)); 4018 } 4019 } 4020 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4021 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4022 PetscFunctionReturn(0); 4023 } 4024 4025 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4026 { 4027 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4028 PetscInt dim, depth, pheight, coneSize; 4029 4030 PetscFunctionBeginHot; 4031 PetscCall(DMGetDimension(dm, &dim)); 4032 PetscCall(DMPlexGetDepth(dm, &depth)); 4033 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4034 pheight = depth - pdepth; 4035 if (depth <= 1) { 4036 switch (pdepth) { 4037 case 0: ct = DM_POLYTOPE_POINT;break; 4038 case 1: 4039 switch (coneSize) { 4040 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4041 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4042 case 4: 4043 switch (dim) { 4044 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4045 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4046 default: break; 4047 } 4048 break; 4049 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4050 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4051 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4052 default: break; 4053 } 4054 } 4055 } else { 4056 if (pdepth == 0) { 4057 ct = DM_POLYTOPE_POINT; 4058 } else if (pheight == 0) { 4059 switch (dim) { 4060 case 1: 4061 switch (coneSize) { 4062 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4063 default: break; 4064 } 4065 break; 4066 case 2: 4067 switch (coneSize) { 4068 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4069 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4070 default: break; 4071 } 4072 break; 4073 case 3: 4074 switch (coneSize) { 4075 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4076 case 5: 4077 { 4078 const PetscInt *cone; 4079 PetscInt faceConeSize; 4080 4081 PetscCall(DMPlexGetCone(dm, p, &cone)); 4082 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4083 switch (faceConeSize) { 4084 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4085 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4086 } 4087 } 4088 break; 4089 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4090 default: break; 4091 } 4092 break; 4093 default: break; 4094 } 4095 } else if (pheight > 0) { 4096 switch (coneSize) { 4097 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4098 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4099 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4100 default: break; 4101 } 4102 } 4103 } 4104 *pt = ct; 4105 PetscFunctionReturn(0); 4106 } 4107 4108 /*@ 4109 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4110 4111 Collective on dm 4112 4113 Input Parameter: 4114 . mesh - The DMPlex 4115 4116 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4117 4118 Level: developer 4119 4120 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4121 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4122 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4123 4124 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4125 @*/ 4126 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4127 { 4128 DM_Plex *mesh; 4129 DMLabel ctLabel; 4130 PetscInt pStart, pEnd, p; 4131 4132 PetscFunctionBegin; 4133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4134 mesh = (DM_Plex *) dm->data; 4135 PetscCall(DMCreateLabel(dm, "celltype")); 4136 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4137 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4138 for (p = pStart; p < pEnd; ++p) { 4139 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4140 PetscInt pdepth; 4141 4142 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4143 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4144 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4145 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4146 } 4147 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4148 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4149 PetscFunctionReturn(0); 4150 } 4151 4152 /*@C 4153 DMPlexGetJoin - Get an array for the join of the set of points 4154 4155 Not Collective 4156 4157 Input Parameters: 4158 + dm - The DMPlex object 4159 . numPoints - The number of input points for the join 4160 - points - The input points 4161 4162 Output Parameters: 4163 + numCoveredPoints - The number of points in the join 4164 - coveredPoints - The points in the join 4165 4166 Level: intermediate 4167 4168 Note: Currently, this is restricted to a single level join 4169 4170 Fortran Notes: 4171 Since it returns an array, this routine is only available in Fortran 90, and you must 4172 include petsc.h90 in your code. 4173 4174 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4175 4176 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4177 @*/ 4178 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4179 { 4180 DM_Plex *mesh = (DM_Plex*) dm->data; 4181 PetscInt *join[2]; 4182 PetscInt joinSize, i = 0; 4183 PetscInt dof, off, p, c, m; 4184 PetscInt maxSupportSize; 4185 4186 PetscFunctionBegin; 4187 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4188 PetscValidIntPointer(points, 3); 4189 PetscValidIntPointer(numCoveredPoints, 4); 4190 PetscValidPointer(coveredPoints, 5); 4191 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4192 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4193 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4194 /* Copy in support of first point */ 4195 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4196 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4197 for (joinSize = 0; joinSize < dof; ++joinSize) { 4198 join[i][joinSize] = mesh->supports[off+joinSize]; 4199 } 4200 /* Check each successive support */ 4201 for (p = 1; p < numPoints; ++p) { 4202 PetscInt newJoinSize = 0; 4203 4204 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4205 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4206 for (c = 0; c < dof; ++c) { 4207 const PetscInt point = mesh->supports[off+c]; 4208 4209 for (m = 0; m < joinSize; ++m) { 4210 if (point == join[i][m]) { 4211 join[1-i][newJoinSize++] = point; 4212 break; 4213 } 4214 } 4215 } 4216 joinSize = newJoinSize; 4217 i = 1-i; 4218 } 4219 *numCoveredPoints = joinSize; 4220 *coveredPoints = join[i]; 4221 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4222 PetscFunctionReturn(0); 4223 } 4224 4225 /*@C 4226 DMPlexRestoreJoin - Restore an array for the join of the set of points 4227 4228 Not Collective 4229 4230 Input Parameters: 4231 + dm - The DMPlex object 4232 . numPoints - The number of input points for the join 4233 - points - The input points 4234 4235 Output Parameters: 4236 + numCoveredPoints - The number of points in the join 4237 - coveredPoints - The points in the join 4238 4239 Fortran Notes: 4240 Since it returns an array, this routine is only available in Fortran 90, and you must 4241 include petsc.h90 in your code. 4242 4243 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4244 4245 Level: intermediate 4246 4247 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4248 @*/ 4249 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4250 { 4251 PetscFunctionBegin; 4252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4253 if (points) PetscValidIntPointer(points,3); 4254 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4255 PetscValidPointer(coveredPoints, 5); 4256 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4257 if (numCoveredPoints) *numCoveredPoints = 0; 4258 PetscFunctionReturn(0); 4259 } 4260 4261 /*@C 4262 DMPlexGetFullJoin - Get an array for the join of the set of points 4263 4264 Not Collective 4265 4266 Input Parameters: 4267 + dm - The DMPlex object 4268 . numPoints - The number of input points for the join 4269 - points - The input points 4270 4271 Output Parameters: 4272 + numCoveredPoints - The number of points in the join 4273 - coveredPoints - The points in the join 4274 4275 Fortran Notes: 4276 Since it returns an array, this routine is only available in Fortran 90, and you must 4277 include petsc.h90 in your code. 4278 4279 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4280 4281 Level: intermediate 4282 4283 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4284 @*/ 4285 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4286 { 4287 PetscInt *offsets, **closures; 4288 PetscInt *join[2]; 4289 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4290 PetscInt p, d, c, m, ms; 4291 4292 PetscFunctionBegin; 4293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4294 PetscValidIntPointer(points, 3); 4295 PetscValidIntPointer(numCoveredPoints, 4); 4296 PetscValidPointer(coveredPoints, 5); 4297 4298 PetscCall(DMPlexGetDepth(dm, &depth)); 4299 PetscCall(PetscCalloc1(numPoints, &closures)); 4300 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4301 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4302 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4303 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4304 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4305 4306 for (p = 0; p < numPoints; ++p) { 4307 PetscInt closureSize; 4308 4309 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4310 4311 offsets[p*(depth+2)+0] = 0; 4312 for (d = 0; d < depth+1; ++d) { 4313 PetscInt pStart, pEnd, i; 4314 4315 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4316 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4317 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4318 offsets[p*(depth+2)+d+1] = i; 4319 break; 4320 } 4321 } 4322 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4323 } 4324 PetscCheck(offsets[p*(depth+2)+depth+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(depth+2)+depth+1], closureSize); 4325 } 4326 for (d = 0; d < depth+1; ++d) { 4327 PetscInt dof; 4328 4329 /* Copy in support of first point */ 4330 dof = offsets[d+1] - offsets[d]; 4331 for (joinSize = 0; joinSize < dof; ++joinSize) { 4332 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4333 } 4334 /* Check each successive cone */ 4335 for (p = 1; p < numPoints && joinSize; ++p) { 4336 PetscInt newJoinSize = 0; 4337 4338 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4339 for (c = 0; c < dof; ++c) { 4340 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4341 4342 for (m = 0; m < joinSize; ++m) { 4343 if (point == join[i][m]) { 4344 join[1-i][newJoinSize++] = point; 4345 break; 4346 } 4347 } 4348 } 4349 joinSize = newJoinSize; 4350 i = 1-i; 4351 } 4352 if (joinSize) break; 4353 } 4354 *numCoveredPoints = joinSize; 4355 *coveredPoints = join[i]; 4356 for (p = 0; p < numPoints; ++p) { 4357 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4358 } 4359 PetscCall(PetscFree(closures)); 4360 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4361 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4362 PetscFunctionReturn(0); 4363 } 4364 4365 /*@C 4366 DMPlexGetMeet - Get an array for the meet of the set of points 4367 4368 Not Collective 4369 4370 Input Parameters: 4371 + dm - The DMPlex object 4372 . numPoints - The number of input points for the meet 4373 - points - The input points 4374 4375 Output Parameters: 4376 + numCoveredPoints - The number of points in the meet 4377 - coveredPoints - The points in the meet 4378 4379 Level: intermediate 4380 4381 Note: Currently, this is restricted to a single level meet 4382 4383 Fortran Notes: 4384 Since it returns an array, this routine is only available in Fortran 90, and you must 4385 include petsc.h90 in your code. 4386 4387 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4388 4389 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4390 @*/ 4391 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4392 { 4393 DM_Plex *mesh = (DM_Plex*) dm->data; 4394 PetscInt *meet[2]; 4395 PetscInt meetSize, i = 0; 4396 PetscInt dof, off, p, c, m; 4397 PetscInt maxConeSize; 4398 4399 PetscFunctionBegin; 4400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4401 PetscValidIntPointer(points, 3); 4402 PetscValidIntPointer(numCoveringPoints, 4); 4403 PetscValidPointer(coveringPoints, 5); 4404 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4405 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4406 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4407 /* Copy in cone of first point */ 4408 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4409 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4410 for (meetSize = 0; meetSize < dof; ++meetSize) { 4411 meet[i][meetSize] = mesh->cones[off+meetSize]; 4412 } 4413 /* Check each successive cone */ 4414 for (p = 1; p < numPoints; ++p) { 4415 PetscInt newMeetSize = 0; 4416 4417 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4418 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4419 for (c = 0; c < dof; ++c) { 4420 const PetscInt point = mesh->cones[off+c]; 4421 4422 for (m = 0; m < meetSize; ++m) { 4423 if (point == meet[i][m]) { 4424 meet[1-i][newMeetSize++] = point; 4425 break; 4426 } 4427 } 4428 } 4429 meetSize = newMeetSize; 4430 i = 1-i; 4431 } 4432 *numCoveringPoints = meetSize; 4433 *coveringPoints = meet[i]; 4434 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4435 PetscFunctionReturn(0); 4436 } 4437 4438 /*@C 4439 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4440 4441 Not Collective 4442 4443 Input Parameters: 4444 + dm - The DMPlex object 4445 . numPoints - The number of input points for the meet 4446 - points - The input points 4447 4448 Output Parameters: 4449 + numCoveredPoints - The number of points in the meet 4450 - coveredPoints - The points in the meet 4451 4452 Level: intermediate 4453 4454 Fortran Notes: 4455 Since it returns an array, this routine is only available in Fortran 90, and you must 4456 include petsc.h90 in your code. 4457 4458 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4459 4460 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4461 @*/ 4462 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4463 { 4464 PetscFunctionBegin; 4465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4466 if (points) PetscValidIntPointer(points,3); 4467 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4468 PetscValidPointer(coveredPoints,5); 4469 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4470 if (numCoveredPoints) *numCoveredPoints = 0; 4471 PetscFunctionReturn(0); 4472 } 4473 4474 /*@C 4475 DMPlexGetFullMeet - Get an array for the meet of the set of points 4476 4477 Not Collective 4478 4479 Input Parameters: 4480 + dm - The DMPlex object 4481 . numPoints - The number of input points for the meet 4482 - points - The input points 4483 4484 Output Parameters: 4485 + numCoveredPoints - The number of points in the meet 4486 - coveredPoints - The points in the meet 4487 4488 Level: intermediate 4489 4490 Fortran Notes: 4491 Since it returns an array, this routine is only available in Fortran 90, and you must 4492 include petsc.h90 in your code. 4493 4494 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4495 4496 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4497 @*/ 4498 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4499 { 4500 PetscInt *offsets, **closures; 4501 PetscInt *meet[2]; 4502 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4503 PetscInt p, h, c, m, mc; 4504 4505 PetscFunctionBegin; 4506 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4507 PetscValidIntPointer(points, 3); 4508 PetscValidIntPointer(numCoveredPoints, 4); 4509 PetscValidPointer(coveredPoints, 5); 4510 4511 PetscCall(DMPlexGetDepth(dm, &height)); 4512 PetscCall(PetscMalloc1(numPoints, &closures)); 4513 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4514 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4515 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4516 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4517 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4518 4519 for (p = 0; p < numPoints; ++p) { 4520 PetscInt closureSize; 4521 4522 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4523 4524 offsets[p*(height+2)+0] = 0; 4525 for (h = 0; h < height+1; ++h) { 4526 PetscInt pStart, pEnd, i; 4527 4528 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4529 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4530 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4531 offsets[p*(height+2)+h+1] = i; 4532 break; 4533 } 4534 } 4535 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4536 } 4537 PetscCheck(offsets[p*(height+2)+height+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(height+2)+height+1], closureSize); 4538 } 4539 for (h = 0; h < height+1; ++h) { 4540 PetscInt dof; 4541 4542 /* Copy in cone of first point */ 4543 dof = offsets[h+1] - offsets[h]; 4544 for (meetSize = 0; meetSize < dof; ++meetSize) { 4545 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4546 } 4547 /* Check each successive cone */ 4548 for (p = 1; p < numPoints && meetSize; ++p) { 4549 PetscInt newMeetSize = 0; 4550 4551 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4552 for (c = 0; c < dof; ++c) { 4553 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4554 4555 for (m = 0; m < meetSize; ++m) { 4556 if (point == meet[i][m]) { 4557 meet[1-i][newMeetSize++] = point; 4558 break; 4559 } 4560 } 4561 } 4562 meetSize = newMeetSize; 4563 i = 1-i; 4564 } 4565 if (meetSize) break; 4566 } 4567 *numCoveredPoints = meetSize; 4568 *coveredPoints = meet[i]; 4569 for (p = 0; p < numPoints; ++p) { 4570 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4571 } 4572 PetscCall(PetscFree(closures)); 4573 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4574 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4575 PetscFunctionReturn(0); 4576 } 4577 4578 /*@C 4579 DMPlexEqual - Determine if two DMs have the same topology 4580 4581 Not Collective 4582 4583 Input Parameters: 4584 + dmA - A DMPlex object 4585 - dmB - A DMPlex object 4586 4587 Output Parameters: 4588 . equal - PETSC_TRUE if the topologies are identical 4589 4590 Level: intermediate 4591 4592 Notes: 4593 We are not solving graph isomorphism, so we do not permutation. 4594 4595 .seealso: `DMPlexGetCone()` 4596 @*/ 4597 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4598 { 4599 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4600 4601 PetscFunctionBegin; 4602 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4603 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4604 PetscValidBoolPointer(equal, 3); 4605 4606 *equal = PETSC_FALSE; 4607 PetscCall(DMPlexGetDepth(dmA, &depth)); 4608 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4609 if (depth != depthB) PetscFunctionReturn(0); 4610 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4611 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4612 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4613 for (p = pStart; p < pEnd; ++p) { 4614 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4615 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4616 4617 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4618 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4619 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4620 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4621 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4622 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4623 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4624 for (c = 0; c < coneSize; ++c) { 4625 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4626 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4627 } 4628 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4629 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4630 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4631 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4632 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4633 for (s = 0; s < supportSize; ++s) { 4634 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4635 } 4636 } 4637 *equal = PETSC_TRUE; 4638 PetscFunctionReturn(0); 4639 } 4640 4641 /*@C 4642 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4643 4644 Not Collective 4645 4646 Input Parameters: 4647 + dm - The DMPlex 4648 . cellDim - The cell dimension 4649 - numCorners - The number of vertices on a cell 4650 4651 Output Parameters: 4652 . numFaceVertices - The number of vertices on a face 4653 4654 Level: developer 4655 4656 Notes: 4657 Of course this can only work for a restricted set of symmetric shapes 4658 4659 .seealso: `DMPlexGetCone()` 4660 @*/ 4661 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4662 { 4663 MPI_Comm comm; 4664 4665 PetscFunctionBegin; 4666 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4667 PetscValidIntPointer(numFaceVertices,4); 4668 switch (cellDim) { 4669 case 0: 4670 *numFaceVertices = 0; 4671 break; 4672 case 1: 4673 *numFaceVertices = 1; 4674 break; 4675 case 2: 4676 switch (numCorners) { 4677 case 3: /* triangle */ 4678 *numFaceVertices = 2; /* Edge has 2 vertices */ 4679 break; 4680 case 4: /* quadrilateral */ 4681 *numFaceVertices = 2; /* Edge has 2 vertices */ 4682 break; 4683 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4684 *numFaceVertices = 3; /* Edge has 3 vertices */ 4685 break; 4686 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4687 *numFaceVertices = 3; /* Edge has 3 vertices */ 4688 break; 4689 default: 4690 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4691 } 4692 break; 4693 case 3: 4694 switch (numCorners) { 4695 case 4: /* tetradehdron */ 4696 *numFaceVertices = 3; /* Face has 3 vertices */ 4697 break; 4698 case 6: /* tet cohesive cells */ 4699 *numFaceVertices = 4; /* Face has 4 vertices */ 4700 break; 4701 case 8: /* hexahedron */ 4702 *numFaceVertices = 4; /* Face has 4 vertices */ 4703 break; 4704 case 9: /* tet cohesive Lagrange cells */ 4705 *numFaceVertices = 6; /* Face has 6 vertices */ 4706 break; 4707 case 10: /* quadratic tetrahedron */ 4708 *numFaceVertices = 6; /* Face has 6 vertices */ 4709 break; 4710 case 12: /* hex cohesive Lagrange cells */ 4711 *numFaceVertices = 6; /* Face has 6 vertices */ 4712 break; 4713 case 18: /* quadratic tet cohesive Lagrange cells */ 4714 *numFaceVertices = 6; /* Face has 6 vertices */ 4715 break; 4716 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4717 *numFaceVertices = 9; /* Face has 9 vertices */ 4718 break; 4719 default: 4720 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4721 } 4722 break; 4723 default: 4724 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4725 } 4726 PetscFunctionReturn(0); 4727 } 4728 4729 /*@ 4730 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4731 4732 Not Collective 4733 4734 Input Parameter: 4735 . dm - The DMPlex object 4736 4737 Output Parameter: 4738 . depthLabel - The DMLabel recording point depth 4739 4740 Level: developer 4741 4742 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4743 @*/ 4744 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4745 { 4746 PetscFunctionBegin; 4747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4748 PetscValidPointer(depthLabel, 2); 4749 *depthLabel = dm->depthLabel; 4750 PetscFunctionReturn(0); 4751 } 4752 4753 /*@ 4754 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4755 4756 Not Collective 4757 4758 Input Parameter: 4759 . dm - The DMPlex object 4760 4761 Output Parameter: 4762 . depth - The number of strata (breadth first levels) in the DAG 4763 4764 Level: developer 4765 4766 Notes: 4767 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4768 The point depth is described more in detail in DMPlexGetDepthStratum(). 4769 An empty mesh gives -1. 4770 4771 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4772 @*/ 4773 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4774 { 4775 DMLabel label; 4776 PetscInt d = 0; 4777 4778 PetscFunctionBegin; 4779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4780 PetscValidIntPointer(depth, 2); 4781 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4782 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4783 *depth = d-1; 4784 PetscFunctionReturn(0); 4785 } 4786 4787 /*@ 4788 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4789 4790 Not Collective 4791 4792 Input Parameters: 4793 + dm - The DMPlex object 4794 - depth - The requested depth 4795 4796 Output Parameters: 4797 + start - The first point at this depth 4798 - end - One beyond the last point at this depth 4799 4800 Notes: 4801 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4802 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4803 higher dimension, e.g., "edges". 4804 4805 Level: developer 4806 4807 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4808 @*/ 4809 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4810 { 4811 DMLabel label; 4812 PetscInt pStart, pEnd; 4813 4814 PetscFunctionBegin; 4815 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4816 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4817 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4818 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4819 if (pStart == pEnd) PetscFunctionReturn(0); 4820 if (depth < 0) { 4821 if (start) *start = pStart; 4822 if (end) *end = pEnd; 4823 PetscFunctionReturn(0); 4824 } 4825 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4826 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4827 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4828 PetscFunctionReturn(0); 4829 } 4830 4831 /*@ 4832 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4833 4834 Not Collective 4835 4836 Input Parameters: 4837 + dm - The DMPlex object 4838 - height - The requested height 4839 4840 Output Parameters: 4841 + start - The first point at this height 4842 - end - One beyond the last point at this height 4843 4844 Notes: 4845 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4846 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4847 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4848 4849 Level: developer 4850 4851 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4852 @*/ 4853 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4854 { 4855 DMLabel label; 4856 PetscInt depth, pStart, pEnd; 4857 4858 PetscFunctionBegin; 4859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4860 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4861 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4862 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4863 if (pStart == pEnd) PetscFunctionReturn(0); 4864 if (height < 0) { 4865 if (start) *start = pStart; 4866 if (end) *end = pEnd; 4867 PetscFunctionReturn(0); 4868 } 4869 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4870 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4871 PetscCall(DMLabelGetNumValues(label, &depth)); 4872 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4873 PetscFunctionReturn(0); 4874 } 4875 4876 /*@ 4877 DMPlexGetPointDepth - Get the depth of a given point 4878 4879 Not Collective 4880 4881 Input Parameters: 4882 + dm - The DMPlex object 4883 - point - The point 4884 4885 Output Parameter: 4886 . depth - The depth of the point 4887 4888 Level: intermediate 4889 4890 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4891 @*/ 4892 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4893 { 4894 PetscFunctionBegin; 4895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4896 PetscValidIntPointer(depth, 3); 4897 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4898 PetscFunctionReturn(0); 4899 } 4900 4901 /*@ 4902 DMPlexGetPointHeight - Get the height of a given point 4903 4904 Not Collective 4905 4906 Input Parameters: 4907 + dm - The DMPlex object 4908 - point - The point 4909 4910 Output Parameter: 4911 . height - The height of the point 4912 4913 Level: intermediate 4914 4915 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4916 @*/ 4917 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4918 { 4919 PetscInt n, pDepth; 4920 4921 PetscFunctionBegin; 4922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4923 PetscValidIntPointer(height, 3); 4924 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4925 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4926 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4927 PetscFunctionReturn(0); 4928 } 4929 4930 /*@ 4931 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4932 4933 Not Collective 4934 4935 Input Parameter: 4936 . dm - The DMPlex object 4937 4938 Output Parameter: 4939 . celltypeLabel - The DMLabel recording cell polytope type 4940 4941 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4942 DMCreateLabel(dm, "celltype") beforehand. 4943 4944 Level: developer 4945 4946 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4947 @*/ 4948 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4949 { 4950 PetscFunctionBegin; 4951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4952 PetscValidPointer(celltypeLabel, 2); 4953 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4954 *celltypeLabel = dm->celltypeLabel; 4955 PetscFunctionReturn(0); 4956 } 4957 4958 /*@ 4959 DMPlexGetCellType - Get the polytope type of a given cell 4960 4961 Not Collective 4962 4963 Input Parameters: 4964 + dm - The DMPlex object 4965 - cell - The cell 4966 4967 Output Parameter: 4968 . celltype - The polytope type of the cell 4969 4970 Level: intermediate 4971 4972 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4973 @*/ 4974 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4975 { 4976 DMLabel label; 4977 PetscInt ct; 4978 4979 PetscFunctionBegin; 4980 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4981 PetscValidPointer(celltype, 3); 4982 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4983 PetscCall(DMLabelGetValue(label, cell, &ct)); 4984 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4985 *celltype = (DMPolytopeType) ct; 4986 PetscFunctionReturn(0); 4987 } 4988 4989 /*@ 4990 DMPlexSetCellType - Set the polytope type of a given cell 4991 4992 Not Collective 4993 4994 Input Parameters: 4995 + dm - The DMPlex object 4996 . cell - The cell 4997 - celltype - The polytope type of the cell 4998 4999 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5000 is executed. This function will override the computed type. However, if automatic classification will not succeed 5001 and a user wants to manually specify all types, the classification must be disabled by calling 5002 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5003 5004 Level: advanced 5005 5006 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5007 @*/ 5008 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5009 { 5010 DMLabel label; 5011 5012 PetscFunctionBegin; 5013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5014 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5015 PetscCall(DMLabelSetValue(label, cell, celltype)); 5016 PetscFunctionReturn(0); 5017 } 5018 5019 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5020 { 5021 PetscSection section, s; 5022 Mat m; 5023 PetscInt maxHeight; 5024 5025 PetscFunctionBegin; 5026 PetscCall(DMClone(dm, cdm)); 5027 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5028 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5029 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5030 PetscCall(DMSetLocalSection(*cdm, section)); 5031 PetscCall(PetscSectionDestroy(§ion)); 5032 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5033 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5034 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5035 PetscCall(PetscSectionDestroy(&s)); 5036 PetscCall(MatDestroy(&m)); 5037 5038 PetscCall(DMSetNumFields(*cdm, 1)); 5039 PetscCall(DMCreateDS(*cdm)); 5040 PetscFunctionReturn(0); 5041 } 5042 5043 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5044 { 5045 Vec coordsLocal; 5046 DM coordsDM; 5047 5048 PetscFunctionBegin; 5049 *field = NULL; 5050 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5051 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5052 if (coordsLocal && coordsDM) { 5053 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5054 } 5055 PetscFunctionReturn(0); 5056 } 5057 5058 /*@C 5059 DMPlexGetConeSection - Return a section which describes the layout of cone data 5060 5061 Not Collective 5062 5063 Input Parameters: 5064 . dm - The DMPlex object 5065 5066 Output Parameter: 5067 . section - The PetscSection object 5068 5069 Level: developer 5070 5071 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5072 @*/ 5073 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5074 { 5075 DM_Plex *mesh = (DM_Plex*) dm->data; 5076 5077 PetscFunctionBegin; 5078 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5079 if (section) *section = mesh->coneSection; 5080 PetscFunctionReturn(0); 5081 } 5082 5083 /*@C 5084 DMPlexGetSupportSection - Return a section which describes the layout of support data 5085 5086 Not Collective 5087 5088 Input Parameters: 5089 . dm - The DMPlex object 5090 5091 Output Parameter: 5092 . section - The PetscSection object 5093 5094 Level: developer 5095 5096 .seealso: `DMPlexGetConeSection()` 5097 @*/ 5098 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5099 { 5100 DM_Plex *mesh = (DM_Plex*) dm->data; 5101 5102 PetscFunctionBegin; 5103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5104 if (section) *section = mesh->supportSection; 5105 PetscFunctionReturn(0); 5106 } 5107 5108 /*@C 5109 DMPlexGetCones - Return cone data 5110 5111 Not Collective 5112 5113 Input Parameters: 5114 . dm - The DMPlex object 5115 5116 Output Parameter: 5117 . cones - The cone for each point 5118 5119 Level: developer 5120 5121 .seealso: `DMPlexGetConeSection()` 5122 @*/ 5123 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5124 { 5125 DM_Plex *mesh = (DM_Plex*) dm->data; 5126 5127 PetscFunctionBegin; 5128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5129 if (cones) *cones = mesh->cones; 5130 PetscFunctionReturn(0); 5131 } 5132 5133 /*@C 5134 DMPlexGetConeOrientations - Return cone orientation data 5135 5136 Not Collective 5137 5138 Input Parameters: 5139 . dm - The DMPlex object 5140 5141 Output Parameter: 5142 . coneOrientations - The array of cone orientations for all points 5143 5144 Level: developer 5145 5146 Notes: 5147 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5148 5149 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5150 5151 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5152 @*/ 5153 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5154 { 5155 DM_Plex *mesh = (DM_Plex*) dm->data; 5156 5157 PetscFunctionBegin; 5158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5159 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5160 PetscFunctionReturn(0); 5161 } 5162 5163 /******************************** FEM Support **********************************/ 5164 5165 /* 5166 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5167 representing a line in the section. 5168 */ 5169 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5170 { 5171 PetscFunctionBeginHot; 5172 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5173 if (line < 0) { 5174 *k = 0; 5175 *Nc = 0; 5176 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5177 *k = 1; 5178 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5179 /* An order k SEM disc has k-1 dofs on an edge */ 5180 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5181 *k = *k / *Nc + 1; 5182 } 5183 PetscFunctionReturn(0); 5184 } 5185 5186 /*@ 5187 5188 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5189 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5190 section provided (or the section of the DM). 5191 5192 Input Parameters: 5193 + dm - The DM 5194 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5195 - section - The PetscSection to reorder, or NULL for the default section 5196 5197 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5198 degree of the basis. 5199 5200 Example: 5201 A typical interpolated single-quad mesh might order points as 5202 .vb 5203 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5204 5205 v4 -- e6 -- v3 5206 | | 5207 e7 c0 e8 5208 | | 5209 v1 -- e5 -- v2 5210 .ve 5211 5212 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5213 dofs in the order of points, e.g., 5214 .vb 5215 c0 -> [0,1,2,3] 5216 v1 -> [4] 5217 ... 5218 e5 -> [8, 9] 5219 .ve 5220 5221 which corresponds to the dofs 5222 .vb 5223 6 10 11 7 5224 13 2 3 15 5225 12 0 1 14 5226 4 8 9 5 5227 .ve 5228 5229 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5230 .vb 5231 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5232 .ve 5233 5234 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5235 .vb 5236 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5237 .ve 5238 5239 Level: developer 5240 5241 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5242 @*/ 5243 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5244 { 5245 DMLabel label; 5246 PetscInt dim, depth = -1, eStart = -1, Nf; 5247 PetscBool vertexchart; 5248 5249 PetscFunctionBegin; 5250 PetscCall(DMGetDimension(dm, &dim)); 5251 if (dim < 1) PetscFunctionReturn(0); 5252 if (point < 0) { 5253 PetscInt sStart,sEnd; 5254 5255 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5256 point = sEnd-sStart ? sStart : point; 5257 } 5258 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5259 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5260 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5261 if (depth == 1) {eStart = point;} 5262 else if (depth == dim) { 5263 const PetscInt *cone; 5264 5265 PetscCall(DMPlexGetCone(dm, point, &cone)); 5266 if (dim == 2) eStart = cone[0]; 5267 else if (dim == 3) { 5268 const PetscInt *cone2; 5269 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5270 eStart = cone2[0]; 5271 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5272 } else PetscCheck(depth < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5273 { /* Determine whether the chart covers all points or just vertices. */ 5274 PetscInt pStart,pEnd,cStart,cEnd; 5275 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5276 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5277 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5278 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5279 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5280 } 5281 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5282 for (PetscInt d=1; d<=dim; d++) { 5283 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5284 PetscInt *perm; 5285 5286 for (f = 0; f < Nf; ++f) { 5287 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5288 size += PetscPowInt(k+1, d)*Nc; 5289 } 5290 PetscCall(PetscMalloc1(size, &perm)); 5291 for (f = 0; f < Nf; ++f) { 5292 switch (d) { 5293 case 1: 5294 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5295 /* 5296 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5297 We want [ vtx0; edge of length k-1; vtx1 ] 5298 */ 5299 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5300 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5301 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5302 foffset = offset; 5303 break; 5304 case 2: 5305 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5306 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5307 /* The SEM order is 5308 5309 v_lb, {e_b}, v_rb, 5310 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5311 v_lt, reverse {e_t}, v_rt 5312 */ 5313 { 5314 const PetscInt of = 0; 5315 const PetscInt oeb = of + PetscSqr(k-1); 5316 const PetscInt oer = oeb + (k-1); 5317 const PetscInt oet = oer + (k-1); 5318 const PetscInt oel = oet + (k-1); 5319 const PetscInt ovlb = oel + (k-1); 5320 const PetscInt ovrb = ovlb + 1; 5321 const PetscInt ovrt = ovrb + 1; 5322 const PetscInt ovlt = ovrt + 1; 5323 PetscInt o; 5324 5325 /* bottom */ 5326 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5327 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5328 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5329 /* middle */ 5330 for (i = 0; i < k-1; ++i) { 5331 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5332 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; 5333 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5334 } 5335 /* top */ 5336 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5337 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5338 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5339 foffset = offset; 5340 } 5341 break; 5342 case 3: 5343 /* The original hex closure is 5344 5345 {c, 5346 f_b, f_t, f_f, f_b, f_r, f_l, 5347 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5348 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5349 */ 5350 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5351 /* The SEM order is 5352 Bottom Slice 5353 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5354 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5355 v_blb, {e_bb}, v_brb, 5356 5357 Middle Slice (j) 5358 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5359 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5360 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5361 5362 Top Slice 5363 v_tlf, {e_tf}, v_trf, 5364 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5365 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5366 */ 5367 { 5368 const PetscInt oc = 0; 5369 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5370 const PetscInt oft = ofb + PetscSqr(k-1); 5371 const PetscInt off = oft + PetscSqr(k-1); 5372 const PetscInt ofk = off + PetscSqr(k-1); 5373 const PetscInt ofr = ofk + PetscSqr(k-1); 5374 const PetscInt ofl = ofr + PetscSqr(k-1); 5375 const PetscInt oebl = ofl + PetscSqr(k-1); 5376 const PetscInt oebb = oebl + (k-1); 5377 const PetscInt oebr = oebb + (k-1); 5378 const PetscInt oebf = oebr + (k-1); 5379 const PetscInt oetf = oebf + (k-1); 5380 const PetscInt oetr = oetf + (k-1); 5381 const PetscInt oetb = oetr + (k-1); 5382 const PetscInt oetl = oetb + (k-1); 5383 const PetscInt oerf = oetl + (k-1); 5384 const PetscInt oelf = oerf + (k-1); 5385 const PetscInt oelb = oelf + (k-1); 5386 const PetscInt oerb = oelb + (k-1); 5387 const PetscInt ovblf = oerb + (k-1); 5388 const PetscInt ovblb = ovblf + 1; 5389 const PetscInt ovbrb = ovblb + 1; 5390 const PetscInt ovbrf = ovbrb + 1; 5391 const PetscInt ovtlf = ovbrf + 1; 5392 const PetscInt ovtrf = ovtlf + 1; 5393 const PetscInt ovtrb = ovtrf + 1; 5394 const PetscInt ovtlb = ovtrb + 1; 5395 PetscInt o, n; 5396 5397 /* Bottom Slice */ 5398 /* bottom */ 5399 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5400 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5401 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5402 /* middle */ 5403 for (i = 0; i < k-1; ++i) { 5404 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5405 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;} 5406 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5407 } 5408 /* top */ 5409 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5410 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5411 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5412 5413 /* Middle Slice */ 5414 for (j = 0; j < k-1; ++j) { 5415 /* bottom */ 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5417 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; 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5419 /* middle */ 5420 for (i = 0; i < k-1; ++i) { 5421 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5422 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; 5423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5424 } 5425 /* top */ 5426 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5427 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; 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5429 } 5430 5431 /* Top Slice */ 5432 /* bottom */ 5433 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5434 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5435 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5436 /* middle */ 5437 for (i = 0; i < k-1; ++i) { 5438 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5439 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5440 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5441 } 5442 /* top */ 5443 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5444 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5445 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5446 5447 foffset = offset; 5448 } 5449 break; 5450 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5451 } 5452 } 5453 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5454 /* Check permutation */ 5455 { 5456 PetscInt *check; 5457 5458 PetscCall(PetscMalloc1(size, &check)); 5459 for (i = 0; i < size; ++i) { 5460 check[i] = -1; 5461 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5462 } 5463 for (i = 0; i < size; ++i) check[perm[i]] = i; 5464 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5465 PetscCall(PetscFree(check)); 5466 } 5467 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5468 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5469 PetscInt *loc_perm; 5470 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5471 for (PetscInt i=0; i<size; i++) { 5472 loc_perm[i] = perm[i]; 5473 loc_perm[size+i] = size + perm[i]; 5474 } 5475 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5476 } 5477 } 5478 PetscFunctionReturn(0); 5479 } 5480 5481 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5482 { 5483 PetscDS prob; 5484 PetscInt depth, Nf, h; 5485 DMLabel label; 5486 5487 PetscFunctionBeginHot; 5488 PetscCall(DMGetDS(dm, &prob)); 5489 Nf = prob->Nf; 5490 label = dm->depthLabel; 5491 *dspace = NULL; 5492 if (field < Nf) { 5493 PetscObject disc = prob->disc[field]; 5494 5495 if (disc->classid == PETSCFE_CLASSID) { 5496 PetscDualSpace dsp; 5497 5498 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5499 PetscCall(DMLabelGetNumValues(label,&depth)); 5500 PetscCall(DMLabelGetValue(label,point,&h)); 5501 h = depth - 1 - h; 5502 if (h) { 5503 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5504 } else { 5505 *dspace = dsp; 5506 } 5507 } 5508 } 5509 PetscFunctionReturn(0); 5510 } 5511 5512 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5513 { 5514 PetscScalar *array, *vArray; 5515 const PetscInt *cone, *coneO; 5516 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5517 5518 PetscFunctionBeginHot; 5519 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5520 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5521 PetscCall(DMPlexGetCone(dm, point, &cone)); 5522 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5523 if (!values || !*values) { 5524 if ((point >= pStart) && (point < pEnd)) { 5525 PetscInt dof; 5526 5527 PetscCall(PetscSectionGetDof(section, point, &dof)); 5528 size += dof; 5529 } 5530 for (p = 0; p < numPoints; ++p) { 5531 const PetscInt cp = cone[p]; 5532 PetscInt dof; 5533 5534 if ((cp < pStart) || (cp >= pEnd)) continue; 5535 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5536 size += dof; 5537 } 5538 if (!values) { 5539 if (csize) *csize = size; 5540 PetscFunctionReturn(0); 5541 } 5542 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5543 } else { 5544 array = *values; 5545 } 5546 size = 0; 5547 PetscCall(VecGetArray(v, &vArray)); 5548 if ((point >= pStart) && (point < pEnd)) { 5549 PetscInt dof, off, d; 5550 PetscScalar *varr; 5551 5552 PetscCall(PetscSectionGetDof(section, point, &dof)); 5553 PetscCall(PetscSectionGetOffset(section, point, &off)); 5554 varr = &vArray[off]; 5555 for (d = 0; d < dof; ++d, ++offset) { 5556 array[offset] = varr[d]; 5557 } 5558 size += dof; 5559 } 5560 for (p = 0; p < numPoints; ++p) { 5561 const PetscInt cp = cone[p]; 5562 PetscInt o = coneO[p]; 5563 PetscInt dof, off, d; 5564 PetscScalar *varr; 5565 5566 if ((cp < pStart) || (cp >= pEnd)) continue; 5567 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5568 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5569 varr = &vArray[off]; 5570 if (o >= 0) { 5571 for (d = 0; d < dof; ++d, ++offset) { 5572 array[offset] = varr[d]; 5573 } 5574 } else { 5575 for (d = dof-1; d >= 0; --d, ++offset) { 5576 array[offset] = varr[d]; 5577 } 5578 } 5579 size += dof; 5580 } 5581 PetscCall(VecRestoreArray(v, &vArray)); 5582 if (!*values) { 5583 if (csize) *csize = size; 5584 *values = array; 5585 } else { 5586 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5587 *csize = size; 5588 } 5589 PetscFunctionReturn(0); 5590 } 5591 5592 /* Compress out points not in the section */ 5593 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5594 { 5595 const PetscInt np = *numPoints; 5596 PetscInt pStart, pEnd, p, q; 5597 5598 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5599 for (p = 0, q = 0; p < np; ++p) { 5600 const PetscInt r = points[p*2]; 5601 if ((r >= pStart) && (r < pEnd)) { 5602 points[q*2] = r; 5603 points[q*2+1] = points[p*2+1]; 5604 ++q; 5605 } 5606 } 5607 *numPoints = q; 5608 return 0; 5609 } 5610 5611 /* Compressed closure does not apply closure permutation */ 5612 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5613 { 5614 const PetscInt *cla = NULL; 5615 PetscInt np, *pts = NULL; 5616 5617 PetscFunctionBeginHot; 5618 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5619 if (*clPoints) { 5620 PetscInt dof, off; 5621 5622 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5623 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5624 PetscCall(ISGetIndices(*clPoints, &cla)); 5625 np = dof/2; 5626 pts = (PetscInt *) &cla[off]; 5627 } else { 5628 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5629 PetscCall(CompressPoints_Private(section, &np, pts)); 5630 } 5631 *numPoints = np; 5632 *points = pts; 5633 *clp = cla; 5634 PetscFunctionReturn(0); 5635 } 5636 5637 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5638 { 5639 PetscFunctionBeginHot; 5640 if (!*clPoints) { 5641 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5642 } else { 5643 PetscCall(ISRestoreIndices(*clPoints, clp)); 5644 } 5645 *numPoints = 0; 5646 *points = NULL; 5647 *clSec = NULL; 5648 *clPoints = NULL; 5649 *clp = NULL; 5650 PetscFunctionReturn(0); 5651 } 5652 5653 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5654 { 5655 PetscInt offset = 0, p; 5656 const PetscInt **perms = NULL; 5657 const PetscScalar **flips = NULL; 5658 5659 PetscFunctionBeginHot; 5660 *size = 0; 5661 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5662 for (p = 0; p < numPoints; p++) { 5663 const PetscInt point = points[2*p]; 5664 const PetscInt *perm = perms ? perms[p] : NULL; 5665 const PetscScalar *flip = flips ? flips[p] : NULL; 5666 PetscInt dof, off, d; 5667 const PetscScalar *varr; 5668 5669 PetscCall(PetscSectionGetDof(section, point, &dof)); 5670 PetscCall(PetscSectionGetOffset(section, point, &off)); 5671 varr = &vArray[off]; 5672 if (clperm) { 5673 if (perm) { 5674 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5675 } else { 5676 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5677 } 5678 if (flip) { 5679 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5680 } 5681 } else { 5682 if (perm) { 5683 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5684 } else { 5685 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5686 } 5687 if (flip) { 5688 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5689 } 5690 } 5691 offset += dof; 5692 } 5693 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5694 *size = offset; 5695 PetscFunctionReturn(0); 5696 } 5697 5698 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[]) 5699 { 5700 PetscInt offset = 0, f; 5701 5702 PetscFunctionBeginHot; 5703 *size = 0; 5704 for (f = 0; f < numFields; ++f) { 5705 PetscInt p; 5706 const PetscInt **perms = NULL; 5707 const PetscScalar **flips = NULL; 5708 5709 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5710 for (p = 0; p < numPoints; p++) { 5711 const PetscInt point = points[2*p]; 5712 PetscInt fdof, foff, b; 5713 const PetscScalar *varr; 5714 const PetscInt *perm = perms ? perms[p] : NULL; 5715 const PetscScalar *flip = flips ? flips[p] : NULL; 5716 5717 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5718 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5719 varr = &vArray[foff]; 5720 if (clperm) { 5721 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5722 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5723 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5724 } else { 5725 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5726 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5727 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5728 } 5729 offset += fdof; 5730 } 5731 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5732 } 5733 *size = offset; 5734 PetscFunctionReturn(0); 5735 } 5736 5737 /*@C 5738 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5739 5740 Not collective 5741 5742 Input Parameters: 5743 + dm - The DM 5744 . section - The section describing the layout in v, or NULL to use the default section 5745 . v - The local vector 5746 - point - The point in the DM 5747 5748 Input/Output Parameters: 5749 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5750 - values - An array to use for the values, or NULL to have it allocated automatically; 5751 if the user provided NULL, it is a borrowed array and should not be freed 5752 5753 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5754 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5755 $ assembly function, and a user may already have allocated storage for this operation. 5756 $ 5757 $ A typical use could be 5758 $ 5759 $ values = NULL; 5760 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5761 $ for (cl = 0; cl < clSize; ++cl) { 5762 $ <Compute on closure> 5763 $ } 5764 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5765 $ 5766 $ or 5767 $ 5768 $ PetscMalloc1(clMaxSize, &values); 5769 $ for (p = pStart; p < pEnd; ++p) { 5770 $ clSize = clMaxSize; 5771 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5772 $ for (cl = 0; cl < clSize; ++cl) { 5773 $ <Compute on closure> 5774 $ } 5775 $ } 5776 $ PetscFree(values); 5777 5778 Fortran Notes: 5779 Since it returns an array, this routine is only available in Fortran 90, and you must 5780 include petsc.h90 in your code. 5781 5782 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5783 5784 Level: intermediate 5785 5786 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5787 @*/ 5788 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5789 { 5790 PetscSection clSection; 5791 IS clPoints; 5792 PetscInt *points = NULL; 5793 const PetscInt *clp, *perm; 5794 PetscInt depth, numFields, numPoints, asize; 5795 5796 PetscFunctionBeginHot; 5797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5798 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5799 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5800 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5801 PetscCall(DMPlexGetDepth(dm, &depth)); 5802 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5803 if (depth == 1 && numFields < 2) { 5804 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5805 PetscFunctionReturn(0); 5806 } 5807 /* Get points */ 5808 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5809 /* Get sizes */ 5810 asize = 0; 5811 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5812 PetscInt dof; 5813 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5814 asize += dof; 5815 } 5816 if (values) { 5817 const PetscScalar *vArray; 5818 PetscInt size; 5819 5820 if (*values) { 5821 PetscCheck(*csize >= asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 5822 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5823 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5824 PetscCall(VecGetArrayRead(v, &vArray)); 5825 /* Get values */ 5826 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5827 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5828 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5829 /* Cleanup array */ 5830 PetscCall(VecRestoreArrayRead(v, &vArray)); 5831 } 5832 if (csize) *csize = asize; 5833 /* Cleanup points */ 5834 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5835 PetscFunctionReturn(0); 5836 } 5837 5838 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5839 { 5840 DMLabel depthLabel; 5841 PetscSection clSection; 5842 IS clPoints; 5843 PetscScalar *array; 5844 const PetscScalar *vArray; 5845 PetscInt *points = NULL; 5846 const PetscInt *clp, *perm = NULL; 5847 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5848 5849 PetscFunctionBeginHot; 5850 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5851 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5852 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5853 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5854 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5855 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5856 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5857 if (mdepth == 1 && numFields < 2) { 5858 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5859 PetscFunctionReturn(0); 5860 } 5861 /* Get points */ 5862 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5863 for (clsize=0,p=0; p<Np; p++) { 5864 PetscInt dof; 5865 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5866 clsize += dof; 5867 } 5868 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5869 /* Filter points */ 5870 for (p = 0; p < numPoints*2; p += 2) { 5871 PetscInt dep; 5872 5873 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5874 if (dep != depth) continue; 5875 points[Np*2+0] = points[p]; 5876 points[Np*2+1] = points[p+1]; 5877 ++Np; 5878 } 5879 /* Get array */ 5880 if (!values || !*values) { 5881 PetscInt asize = 0, dof; 5882 5883 for (p = 0; p < Np*2; p += 2) { 5884 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5885 asize += dof; 5886 } 5887 if (!values) { 5888 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5889 if (csize) *csize = asize; 5890 PetscFunctionReturn(0); 5891 } 5892 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5893 } else { 5894 array = *values; 5895 } 5896 PetscCall(VecGetArrayRead(v, &vArray)); 5897 /* Get values */ 5898 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5899 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5900 /* Cleanup points */ 5901 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5902 /* Cleanup array */ 5903 PetscCall(VecRestoreArrayRead(v, &vArray)); 5904 if (!*values) { 5905 if (csize) *csize = size; 5906 *values = array; 5907 } else { 5908 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5909 *csize = size; 5910 } 5911 PetscFunctionReturn(0); 5912 } 5913 5914 /*@C 5915 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5916 5917 Not collective 5918 5919 Input Parameters: 5920 + dm - The DM 5921 . section - The section describing the layout in v, or NULL to use the default section 5922 . v - The local vector 5923 . point - The point in the DM 5924 . csize - The number of values in the closure, or NULL 5925 - values - The array of values, which is a borrowed array and should not be freed 5926 5927 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5928 5929 Fortran Notes: 5930 Since it returns an array, this routine is only available in Fortran 90, and you must 5931 include petsc.h90 in your code. 5932 5933 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5934 5935 Level: intermediate 5936 5937 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5938 @*/ 5939 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5940 { 5941 PetscInt size = 0; 5942 5943 PetscFunctionBegin; 5944 /* Should work without recalculating size */ 5945 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5946 *values = NULL; 5947 PetscFunctionReturn(0); 5948 } 5949 5950 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5951 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5952 5953 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[]) 5954 { 5955 PetscInt cdof; /* The number of constraints on this point */ 5956 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5957 PetscScalar *a; 5958 PetscInt off, cind = 0, k; 5959 5960 PetscFunctionBegin; 5961 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5962 PetscCall(PetscSectionGetOffset(section, point, &off)); 5963 a = &array[off]; 5964 if (!cdof || setBC) { 5965 if (clperm) { 5966 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5967 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5968 } else { 5969 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5970 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5971 } 5972 } else { 5973 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5974 if (clperm) { 5975 if (perm) {for (k = 0; k < dof; ++k) { 5976 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5977 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5978 } 5979 } else { 5980 for (k = 0; k < dof; ++k) { 5981 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5982 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5983 } 5984 } 5985 } else { 5986 if (perm) { 5987 for (k = 0; k < dof; ++k) { 5988 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5989 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5990 } 5991 } else { 5992 for (k = 0; k < dof; ++k) { 5993 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5994 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5995 } 5996 } 5997 } 5998 } 5999 PetscFunctionReturn(0); 6000 } 6001 6002 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[]) 6003 { 6004 PetscInt cdof; /* The number of constraints on this point */ 6005 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6006 PetscScalar *a; 6007 PetscInt off, cind = 0, k; 6008 6009 PetscFunctionBegin; 6010 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6011 PetscCall(PetscSectionGetOffset(section, point, &off)); 6012 a = &array[off]; 6013 if (cdof) { 6014 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6015 if (clperm) { 6016 if (perm) { 6017 for (k = 0; k < dof; ++k) { 6018 if ((cind < cdof) && (k == cdofs[cind])) { 6019 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6020 cind++; 6021 } 6022 } 6023 } else { 6024 for (k = 0; k < dof; ++k) { 6025 if ((cind < cdof) && (k == cdofs[cind])) { 6026 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6027 cind++; 6028 } 6029 } 6030 } 6031 } else { 6032 if (perm) { 6033 for (k = 0; k < dof; ++k) { 6034 if ((cind < cdof) && (k == cdofs[cind])) { 6035 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6036 cind++; 6037 } 6038 } 6039 } else { 6040 for (k = 0; k < dof; ++k) { 6041 if ((cind < cdof) && (k == cdofs[cind])) { 6042 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6043 cind++; 6044 } 6045 } 6046 } 6047 } 6048 } 6049 PetscFunctionReturn(0); 6050 } 6051 6052 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[]) 6053 { 6054 PetscScalar *a; 6055 PetscInt fdof, foff, fcdof, foffset = *offset; 6056 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6057 PetscInt cind = 0, b; 6058 6059 PetscFunctionBegin; 6060 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6061 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6062 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6063 a = &array[foff]; 6064 if (!fcdof || setBC) { 6065 if (clperm) { 6066 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6067 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6068 } else { 6069 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6070 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6071 } 6072 } else { 6073 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6074 if (clperm) { 6075 if (perm) { 6076 for (b = 0; b < fdof; b++) { 6077 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6078 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6079 } 6080 } else { 6081 for (b = 0; b < fdof; b++) { 6082 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6083 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6084 } 6085 } 6086 } else { 6087 if (perm) { 6088 for (b = 0; b < fdof; b++) { 6089 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6090 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6091 } 6092 } else { 6093 for (b = 0; b < fdof; b++) { 6094 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6095 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6096 } 6097 } 6098 } 6099 } 6100 *offset += fdof; 6101 PetscFunctionReturn(0); 6102 } 6103 6104 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[]) 6105 { 6106 PetscScalar *a; 6107 PetscInt fdof, foff, fcdof, foffset = *offset; 6108 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6109 PetscInt Nc, cind = 0, ncind = 0, b; 6110 PetscBool ncSet, fcSet; 6111 6112 PetscFunctionBegin; 6113 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6114 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6115 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6116 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6117 a = &array[foff]; 6118 if (fcdof) { 6119 /* We just override fcdof and fcdofs with Ncc and comps */ 6120 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6121 if (clperm) { 6122 if (perm) { 6123 if (comps) { 6124 for (b = 0; b < fdof; b++) { 6125 ncSet = fcSet = PETSC_FALSE; 6126 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6127 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6128 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6129 } 6130 } else { 6131 for (b = 0; b < fdof; b++) { 6132 if ((cind < fcdof) && (b == fcdofs[cind])) { 6133 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6134 ++cind; 6135 } 6136 } 6137 } 6138 } else { 6139 if (comps) { 6140 for (b = 0; b < fdof; b++) { 6141 ncSet = fcSet = PETSC_FALSE; 6142 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6143 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6144 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6145 } 6146 } else { 6147 for (b = 0; b < fdof; b++) { 6148 if ((cind < fcdof) && (b == fcdofs[cind])) { 6149 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6150 ++cind; 6151 } 6152 } 6153 } 6154 } 6155 } else { 6156 if (perm) { 6157 if (comps) { 6158 for (b = 0; b < fdof; b++) { 6159 ncSet = fcSet = PETSC_FALSE; 6160 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6161 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6162 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6163 } 6164 } else { 6165 for (b = 0; b < fdof; b++) { 6166 if ((cind < fcdof) && (b == fcdofs[cind])) { 6167 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6168 ++cind; 6169 } 6170 } 6171 } 6172 } else { 6173 if (comps) { 6174 for (b = 0; b < fdof; b++) { 6175 ncSet = fcSet = PETSC_FALSE; 6176 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6177 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6178 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6179 } 6180 } else { 6181 for (b = 0; b < fdof; b++) { 6182 if ((cind < fcdof) && (b == fcdofs[cind])) { 6183 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6184 ++cind; 6185 } 6186 } 6187 } 6188 } 6189 } 6190 } 6191 *offset += fdof; 6192 PetscFunctionReturn(0); 6193 } 6194 6195 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6196 { 6197 PetscScalar *array; 6198 const PetscInt *cone, *coneO; 6199 PetscInt pStart, pEnd, p, numPoints, off, dof; 6200 6201 PetscFunctionBeginHot; 6202 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6203 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6204 PetscCall(DMPlexGetCone(dm, point, &cone)); 6205 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6206 PetscCall(VecGetArray(v, &array)); 6207 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6208 const PetscInt cp = !p ? point : cone[p-1]; 6209 const PetscInt o = !p ? 0 : coneO[p-1]; 6210 6211 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6212 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6213 /* ADD_VALUES */ 6214 { 6215 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6216 PetscScalar *a; 6217 PetscInt cdof, coff, cind = 0, k; 6218 6219 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6220 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6221 a = &array[coff]; 6222 if (!cdof) { 6223 if (o >= 0) { 6224 for (k = 0; k < dof; ++k) { 6225 a[k] += values[off+k]; 6226 } 6227 } else { 6228 for (k = 0; k < dof; ++k) { 6229 a[k] += values[off+dof-k-1]; 6230 } 6231 } 6232 } else { 6233 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6234 if (o >= 0) { 6235 for (k = 0; k < dof; ++k) { 6236 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6237 a[k] += values[off+k]; 6238 } 6239 } else { 6240 for (k = 0; k < dof; ++k) { 6241 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6242 a[k] += values[off+dof-k-1]; 6243 } 6244 } 6245 } 6246 } 6247 } 6248 PetscCall(VecRestoreArray(v, &array)); 6249 PetscFunctionReturn(0); 6250 } 6251 6252 /*@C 6253 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6254 6255 Not collective 6256 6257 Input Parameters: 6258 + dm - The DM 6259 . section - The section describing the layout in v, or NULL to use the default section 6260 . v - The local vector 6261 . point - The point in the DM 6262 . values - The array of values 6263 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6264 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6265 6266 Fortran Notes: 6267 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6268 6269 Level: intermediate 6270 6271 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6272 @*/ 6273 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6274 { 6275 PetscSection clSection; 6276 IS clPoints; 6277 PetscScalar *array; 6278 PetscInt *points = NULL; 6279 const PetscInt *clp, *clperm = NULL; 6280 PetscInt depth, numFields, numPoints, p, clsize; 6281 6282 PetscFunctionBeginHot; 6283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6284 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6285 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6286 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6287 PetscCall(DMPlexGetDepth(dm, &depth)); 6288 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6289 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6290 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6291 PetscFunctionReturn(0); 6292 } 6293 /* Get points */ 6294 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6295 for (clsize=0,p=0; p<numPoints; p++) { 6296 PetscInt dof; 6297 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6298 clsize += dof; 6299 } 6300 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6301 /* Get array */ 6302 PetscCall(VecGetArray(v, &array)); 6303 /* Get values */ 6304 if (numFields > 0) { 6305 PetscInt offset = 0, f; 6306 for (f = 0; f < numFields; ++f) { 6307 const PetscInt **perms = NULL; 6308 const PetscScalar **flips = NULL; 6309 6310 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6311 switch (mode) { 6312 case INSERT_VALUES: 6313 for (p = 0; p < numPoints; p++) { 6314 const PetscInt point = points[2*p]; 6315 const PetscInt *perm = perms ? perms[p] : NULL; 6316 const PetscScalar *flip = flips ? flips[p] : NULL; 6317 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6318 } break; 6319 case INSERT_ALL_VALUES: 6320 for (p = 0; p < numPoints; p++) { 6321 const PetscInt point = points[2*p]; 6322 const PetscInt *perm = perms ? perms[p] : NULL; 6323 const PetscScalar *flip = flips ? flips[p] : NULL; 6324 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6325 } break; 6326 case INSERT_BC_VALUES: 6327 for (p = 0; p < numPoints; p++) { 6328 const PetscInt point = points[2*p]; 6329 const PetscInt *perm = perms ? perms[p] : NULL; 6330 const PetscScalar *flip = flips ? flips[p] : NULL; 6331 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6332 } break; 6333 case ADD_VALUES: 6334 for (p = 0; p < numPoints; p++) { 6335 const PetscInt point = points[2*p]; 6336 const PetscInt *perm = perms ? perms[p] : NULL; 6337 const PetscScalar *flip = flips ? flips[p] : NULL; 6338 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6339 } break; 6340 case ADD_ALL_VALUES: 6341 for (p = 0; p < numPoints; p++) { 6342 const PetscInt point = points[2*p]; 6343 const PetscInt *perm = perms ? perms[p] : NULL; 6344 const PetscScalar *flip = flips ? flips[p] : NULL; 6345 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6346 } break; 6347 case ADD_BC_VALUES: 6348 for (p = 0; p < numPoints; p++) { 6349 const PetscInt point = points[2*p]; 6350 const PetscInt *perm = perms ? perms[p] : NULL; 6351 const PetscScalar *flip = flips ? flips[p] : NULL; 6352 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6353 } break; 6354 default: 6355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6356 } 6357 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6358 } 6359 } else { 6360 PetscInt dof, off; 6361 const PetscInt **perms = NULL; 6362 const PetscScalar **flips = NULL; 6363 6364 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6365 switch (mode) { 6366 case INSERT_VALUES: 6367 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6368 const PetscInt point = points[2*p]; 6369 const PetscInt *perm = perms ? perms[p] : NULL; 6370 const PetscScalar *flip = flips ? flips[p] : NULL; 6371 PetscCall(PetscSectionGetDof(section, point, &dof)); 6372 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6373 } break; 6374 case INSERT_ALL_VALUES: 6375 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6376 const PetscInt point = points[2*p]; 6377 const PetscInt *perm = perms ? perms[p] : NULL; 6378 const PetscScalar *flip = flips ? flips[p] : NULL; 6379 PetscCall(PetscSectionGetDof(section, point, &dof)); 6380 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6381 } break; 6382 case INSERT_BC_VALUES: 6383 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6384 const PetscInt point = points[2*p]; 6385 const PetscInt *perm = perms ? perms[p] : NULL; 6386 const PetscScalar *flip = flips ? flips[p] : NULL; 6387 PetscCall(PetscSectionGetDof(section, point, &dof)); 6388 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6389 } break; 6390 case ADD_VALUES: 6391 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6392 const PetscInt point = points[2*p]; 6393 const PetscInt *perm = perms ? perms[p] : NULL; 6394 const PetscScalar *flip = flips ? flips[p] : NULL; 6395 PetscCall(PetscSectionGetDof(section, point, &dof)); 6396 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6397 } break; 6398 case ADD_ALL_VALUES: 6399 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6400 const PetscInt point = points[2*p]; 6401 const PetscInt *perm = perms ? perms[p] : NULL; 6402 const PetscScalar *flip = flips ? flips[p] : NULL; 6403 PetscCall(PetscSectionGetDof(section, point, &dof)); 6404 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6405 } break; 6406 case ADD_BC_VALUES: 6407 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6408 const PetscInt point = points[2*p]; 6409 const PetscInt *perm = perms ? perms[p] : NULL; 6410 const PetscScalar *flip = flips ? flips[p] : NULL; 6411 PetscCall(PetscSectionGetDof(section, point, &dof)); 6412 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6413 } break; 6414 default: 6415 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6416 } 6417 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6418 } 6419 /* Cleanup points */ 6420 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6421 /* Cleanup array */ 6422 PetscCall(VecRestoreArray(v, &array)); 6423 PetscFunctionReturn(0); 6424 } 6425 6426 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6427 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6428 { 6429 PetscFunctionBegin; 6430 if (label) { 6431 PetscInt val, fdof; 6432 6433 /* There is a problem with this: 6434 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6435 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6436 Thus I am only going to check val != -1, not val != labelId 6437 */ 6438 PetscCall(DMLabelGetValue(label, point, &val)); 6439 if (val < 0) { 6440 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6441 *offset += fdof; 6442 PetscFunctionReturn(1); 6443 } 6444 } 6445 PetscFunctionReturn(0); 6446 } 6447 6448 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6449 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) 6450 { 6451 PetscSection clSection; 6452 IS clPoints; 6453 PetscScalar *array; 6454 PetscInt *points = NULL; 6455 const PetscInt *clp; 6456 PetscInt numFields, numPoints, p; 6457 PetscInt offset = 0, f; 6458 6459 PetscFunctionBeginHot; 6460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6461 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6462 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6463 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6464 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6465 /* Get points */ 6466 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6467 /* Get array */ 6468 PetscCall(VecGetArray(v, &array)); 6469 /* Get values */ 6470 for (f = 0; f < numFields; ++f) { 6471 const PetscInt **perms = NULL; 6472 const PetscScalar **flips = NULL; 6473 6474 if (!fieldActive[f]) { 6475 for (p = 0; p < numPoints*2; p += 2) { 6476 PetscInt fdof; 6477 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6478 offset += fdof; 6479 } 6480 continue; 6481 } 6482 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6483 switch (mode) { 6484 case INSERT_VALUES: 6485 for (p = 0; p < numPoints; p++) { 6486 const PetscInt point = points[2*p]; 6487 const PetscInt *perm = perms ? perms[p] : NULL; 6488 const PetscScalar *flip = flips ? flips[p] : NULL; 6489 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6490 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6491 } break; 6492 case INSERT_ALL_VALUES: 6493 for (p = 0; p < numPoints; p++) { 6494 const PetscInt point = points[2*p]; 6495 const PetscInt *perm = perms ? perms[p] : NULL; 6496 const PetscScalar *flip = flips ? flips[p] : NULL; 6497 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6498 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6499 } break; 6500 case INSERT_BC_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2*p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6506 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6507 } break; 6508 case ADD_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2*p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6514 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6515 } break; 6516 case ADD_ALL_VALUES: 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2*p]; 6519 const PetscInt *perm = perms ? perms[p] : NULL; 6520 const PetscScalar *flip = flips ? flips[p] : NULL; 6521 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6522 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6523 } break; 6524 default: 6525 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6526 } 6527 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6528 } 6529 /* Cleanup points */ 6530 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6531 /* Cleanup array */ 6532 PetscCall(VecRestoreArray(v, &array)); 6533 PetscFunctionReturn(0); 6534 } 6535 6536 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6537 { 6538 PetscMPIInt rank; 6539 PetscInt i, j; 6540 6541 PetscFunctionBegin; 6542 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6543 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6544 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6545 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6546 numCIndices = numCIndices ? numCIndices : numRIndices; 6547 if (!values) PetscFunctionReturn(0); 6548 for (i = 0; i < numRIndices; i++) { 6549 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6550 for (j = 0; j < numCIndices; j++) { 6551 #if defined(PETSC_USE_COMPLEX) 6552 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6553 #else 6554 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6555 #endif 6556 } 6557 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6558 } 6559 PetscFunctionReturn(0); 6560 } 6561 6562 /* 6563 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6564 6565 Input Parameters: 6566 + section - The section for this data layout 6567 . islocal - Is the section (and thus indices being requested) local or global? 6568 . point - The point contributing dofs with these indices 6569 . off - The global offset of this point 6570 . loff - The local offset of each field 6571 . setBC - The flag determining whether to include indices of boundary values 6572 . perm - A permutation of the dofs on this point, or NULL 6573 - indperm - A permutation of the entire indices array, or NULL 6574 6575 Output Parameter: 6576 . indices - Indices for dofs on this point 6577 6578 Level: developer 6579 6580 Note: The indices could be local or global, depending on the value of 'off'. 6581 */ 6582 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6583 { 6584 PetscInt dof; /* The number of unknowns on this point */ 6585 PetscInt cdof; /* The number of constraints on this point */ 6586 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6587 PetscInt cind = 0, k; 6588 6589 PetscFunctionBegin; 6590 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6591 PetscCall(PetscSectionGetDof(section, point, &dof)); 6592 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6593 if (!cdof || setBC) { 6594 for (k = 0; k < dof; ++k) { 6595 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6596 const PetscInt ind = indperm ? indperm[preind] : preind; 6597 6598 indices[ind] = off + k; 6599 } 6600 } else { 6601 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6602 for (k = 0; k < dof; ++k) { 6603 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6604 const PetscInt ind = indperm ? indperm[preind] : preind; 6605 6606 if ((cind < cdof) && (k == cdofs[cind])) { 6607 /* Insert check for returning constrained indices */ 6608 indices[ind] = -(off+k+1); 6609 ++cind; 6610 } else { 6611 indices[ind] = off + k - (islocal ? 0 : cind); 6612 } 6613 } 6614 } 6615 *loff += dof; 6616 PetscFunctionReturn(0); 6617 } 6618 6619 /* 6620 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6621 6622 Input Parameters: 6623 + section - a section (global or local) 6624 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6625 . point - point within section 6626 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6627 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6628 . setBC - identify constrained (boundary condition) points via involution. 6629 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6630 . permsoff - offset 6631 - indperm - index permutation 6632 6633 Output Parameter: 6634 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6635 . indices - array to hold indices (as defined by section) of each dof associated with point 6636 6637 Notes: 6638 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6639 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6640 in the local vector. 6641 6642 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6643 significant). It is invalid to call with a global section and setBC=true. 6644 6645 Developer Note: 6646 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6647 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6648 offset could be obtained from the section instead of passing it explicitly as we do now. 6649 6650 Example: 6651 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6652 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6653 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6654 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. 6655 6656 Level: developer 6657 */ 6658 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[]) 6659 { 6660 PetscInt numFields, foff, f; 6661 6662 PetscFunctionBegin; 6663 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6664 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6665 for (f = 0, foff = 0; f < numFields; ++f) { 6666 PetscInt fdof, cfdof; 6667 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6668 PetscInt cind = 0, b; 6669 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6670 6671 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6672 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6673 if (!cfdof || setBC) { 6674 for (b = 0; b < fdof; ++b) { 6675 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6676 const PetscInt ind = indperm ? indperm[preind] : preind; 6677 6678 indices[ind] = off+foff+b; 6679 } 6680 } else { 6681 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6682 for (b = 0; b < fdof; ++b) { 6683 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6684 const PetscInt ind = indperm ? indperm[preind] : preind; 6685 6686 if ((cind < cfdof) && (b == fcdofs[cind])) { 6687 indices[ind] = -(off+foff+b+1); 6688 ++cind; 6689 } else { 6690 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6691 } 6692 } 6693 } 6694 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6695 foffs[f] += fdof; 6696 } 6697 PetscFunctionReturn(0); 6698 } 6699 6700 /* 6701 This version believes the globalSection offsets for each field, rather than just the point offset 6702 6703 . foffs - The offset into 'indices' for each field, since it is segregated by field 6704 6705 Notes: 6706 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6707 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6708 */ 6709 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6710 { 6711 PetscInt numFields, foff, f; 6712 6713 PetscFunctionBegin; 6714 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6715 for (f = 0; f < numFields; ++f) { 6716 PetscInt fdof, cfdof; 6717 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6718 PetscInt cind = 0, b; 6719 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6720 6721 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6722 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6723 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6724 if (!cfdof) { 6725 for (b = 0; b < fdof; ++b) { 6726 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6727 const PetscInt ind = indperm ? indperm[preind] : preind; 6728 6729 indices[ind] = foff+b; 6730 } 6731 } else { 6732 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6733 for (b = 0; b < fdof; ++b) { 6734 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6735 const PetscInt ind = indperm ? indperm[preind] : preind; 6736 6737 if ((cind < cfdof) && (b == fcdofs[cind])) { 6738 indices[ind] = -(foff+b+1); 6739 ++cind; 6740 } else { 6741 indices[ind] = foff+b-cind; 6742 } 6743 } 6744 } 6745 foffs[f] += fdof; 6746 } 6747 PetscFunctionReturn(0); 6748 } 6749 6750 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) 6751 { 6752 Mat cMat; 6753 PetscSection aSec, cSec; 6754 IS aIS; 6755 PetscInt aStart = -1, aEnd = -1; 6756 const PetscInt *anchors; 6757 PetscInt numFields, f, p, q, newP = 0; 6758 PetscInt newNumPoints = 0, newNumIndices = 0; 6759 PetscInt *newPoints, *indices, *newIndices; 6760 PetscInt maxAnchor, maxDof; 6761 PetscInt newOffsets[32]; 6762 PetscInt *pointMatOffsets[32]; 6763 PetscInt *newPointOffsets[32]; 6764 PetscScalar *pointMat[32]; 6765 PetscScalar *newValues=NULL,*tmpValues; 6766 PetscBool anyConstrained = PETSC_FALSE; 6767 6768 PetscFunctionBegin; 6769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6770 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6771 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6772 6773 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6774 /* if there are point-to-point constraints */ 6775 if (aSec) { 6776 PetscCall(PetscArrayzero(newOffsets, 32)); 6777 PetscCall(ISGetIndices(aIS,&anchors)); 6778 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6779 /* figure out how many points are going to be in the new element matrix 6780 * (we allow double counting, because it's all just going to be summed 6781 * into the global matrix anyway) */ 6782 for (p = 0; p < 2*numPoints; p+=2) { 6783 PetscInt b = points[p]; 6784 PetscInt bDof = 0, bSecDof; 6785 6786 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6787 if (!bSecDof) { 6788 continue; 6789 } 6790 if (b >= aStart && b < aEnd) { 6791 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6792 } 6793 if (bDof) { 6794 /* this point is constrained */ 6795 /* it is going to be replaced by its anchors */ 6796 PetscInt bOff, q; 6797 6798 anyConstrained = PETSC_TRUE; 6799 newNumPoints += bDof; 6800 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6801 for (q = 0; q < bDof; q++) { 6802 PetscInt a = anchors[bOff + q]; 6803 PetscInt aDof; 6804 6805 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6806 newNumIndices += aDof; 6807 for (f = 0; f < numFields; ++f) { 6808 PetscInt fDof; 6809 6810 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6811 newOffsets[f+1] += fDof; 6812 } 6813 } 6814 } 6815 else { 6816 /* this point is not constrained */ 6817 newNumPoints++; 6818 newNumIndices += bSecDof; 6819 for (f = 0; f < numFields; ++f) { 6820 PetscInt fDof; 6821 6822 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6823 newOffsets[f+1] += fDof; 6824 } 6825 } 6826 } 6827 } 6828 if (!anyConstrained) { 6829 if (outNumPoints) *outNumPoints = 0; 6830 if (outNumIndices) *outNumIndices = 0; 6831 if (outPoints) *outPoints = NULL; 6832 if (outValues) *outValues = NULL; 6833 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6834 PetscFunctionReturn(0); 6835 } 6836 6837 if (outNumPoints) *outNumPoints = newNumPoints; 6838 if (outNumIndices) *outNumIndices = newNumIndices; 6839 6840 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6841 6842 if (!outPoints && !outValues) { 6843 if (offsets) { 6844 for (f = 0; f <= numFields; f++) { 6845 offsets[f] = newOffsets[f]; 6846 } 6847 } 6848 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6849 PetscFunctionReturn(0); 6850 } 6851 6852 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6853 6854 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6855 6856 /* workspaces */ 6857 if (numFields) { 6858 for (f = 0; f < numFields; f++) { 6859 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6860 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6861 } 6862 } 6863 else { 6864 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6865 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6866 } 6867 6868 /* get workspaces for the point-to-point matrices */ 6869 if (numFields) { 6870 PetscInt totalOffset, totalMatOffset; 6871 6872 for (p = 0; p < numPoints; p++) { 6873 PetscInt b = points[2*p]; 6874 PetscInt bDof = 0, bSecDof; 6875 6876 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6877 if (!bSecDof) { 6878 for (f = 0; f < numFields; f++) { 6879 newPointOffsets[f][p + 1] = 0; 6880 pointMatOffsets[f][p + 1] = 0; 6881 } 6882 continue; 6883 } 6884 if (b >= aStart && b < aEnd) { 6885 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6886 } 6887 if (bDof) { 6888 for (f = 0; f < numFields; f++) { 6889 PetscInt fDof, q, bOff, allFDof = 0; 6890 6891 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6892 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6893 for (q = 0; q < bDof; q++) { 6894 PetscInt a = anchors[bOff + q]; 6895 PetscInt aFDof; 6896 6897 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6898 allFDof += aFDof; 6899 } 6900 newPointOffsets[f][p+1] = allFDof; 6901 pointMatOffsets[f][p+1] = fDof * allFDof; 6902 } 6903 } 6904 else { 6905 for (f = 0; f < numFields; f++) { 6906 PetscInt fDof; 6907 6908 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6909 newPointOffsets[f][p+1] = fDof; 6910 pointMatOffsets[f][p+1] = 0; 6911 } 6912 } 6913 } 6914 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6915 newPointOffsets[f][0] = totalOffset; 6916 pointMatOffsets[f][0] = totalMatOffset; 6917 for (p = 0; p < numPoints; p++) { 6918 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6919 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6920 } 6921 totalOffset = newPointOffsets[f][numPoints]; 6922 totalMatOffset = pointMatOffsets[f][numPoints]; 6923 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6924 } 6925 } 6926 else { 6927 for (p = 0; p < numPoints; p++) { 6928 PetscInt b = points[2*p]; 6929 PetscInt bDof = 0, bSecDof; 6930 6931 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6932 if (!bSecDof) { 6933 newPointOffsets[0][p + 1] = 0; 6934 pointMatOffsets[0][p + 1] = 0; 6935 continue; 6936 } 6937 if (b >= aStart && b < aEnd) { 6938 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6939 } 6940 if (bDof) { 6941 PetscInt bOff, q, allDof = 0; 6942 6943 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6944 for (q = 0; q < bDof; q++) { 6945 PetscInt a = anchors[bOff + q], aDof; 6946 6947 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6948 allDof += aDof; 6949 } 6950 newPointOffsets[0][p+1] = allDof; 6951 pointMatOffsets[0][p+1] = bSecDof * allDof; 6952 } 6953 else { 6954 newPointOffsets[0][p+1] = bSecDof; 6955 pointMatOffsets[0][p+1] = 0; 6956 } 6957 } 6958 newPointOffsets[0][0] = 0; 6959 pointMatOffsets[0][0] = 0; 6960 for (p = 0; p < numPoints; p++) { 6961 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6962 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6963 } 6964 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6965 } 6966 6967 /* output arrays */ 6968 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6969 6970 /* get the point-to-point matrices; construct newPoints */ 6971 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6972 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6973 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6974 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6975 if (numFields) { 6976 for (p = 0, newP = 0; p < numPoints; p++) { 6977 PetscInt b = points[2*p]; 6978 PetscInt o = points[2*p+1]; 6979 PetscInt bDof = 0, bSecDof; 6980 6981 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6982 if (!bSecDof) { 6983 continue; 6984 } 6985 if (b >= aStart && b < aEnd) { 6986 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6987 } 6988 if (bDof) { 6989 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6990 6991 fStart[0] = 0; 6992 fEnd[0] = 0; 6993 for (f = 0; f < numFields; f++) { 6994 PetscInt fDof; 6995 6996 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6997 fStart[f+1] = fStart[f] + fDof; 6998 fEnd[f+1] = fStart[f+1]; 6999 } 7000 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7001 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7002 7003 fAnchorStart[0] = 0; 7004 fAnchorEnd[0] = 0; 7005 for (f = 0; f < numFields; f++) { 7006 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7007 7008 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 7009 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 7010 } 7011 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7012 for (q = 0; q < bDof; q++) { 7013 PetscInt a = anchors[bOff + q], aOff; 7014 7015 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7016 newPoints[2*(newP + q)] = a; 7017 newPoints[2*(newP + q) + 1] = 0; 7018 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7019 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7020 } 7021 newP += bDof; 7022 7023 if (outValues) { 7024 /* get the point-to-point submatrix */ 7025 for (f = 0; f < numFields; f++) { 7026 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7027 } 7028 } 7029 } 7030 else { 7031 newPoints[2 * newP] = b; 7032 newPoints[2 * newP + 1] = o; 7033 newP++; 7034 } 7035 } 7036 } else { 7037 for (p = 0; p < numPoints; p++) { 7038 PetscInt b = points[2*p]; 7039 PetscInt o = points[2*p+1]; 7040 PetscInt bDof = 0, bSecDof; 7041 7042 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7043 if (!bSecDof) { 7044 continue; 7045 } 7046 if (b >= aStart && b < aEnd) { 7047 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7048 } 7049 if (bDof) { 7050 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7051 7052 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7053 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7054 7055 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7056 for (q = 0; q < bDof; q++) { 7057 PetscInt a = anchors[bOff + q], aOff; 7058 7059 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7060 7061 newPoints[2*(newP + q)] = a; 7062 newPoints[2*(newP + q) + 1] = 0; 7063 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7064 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7065 } 7066 newP += bDof; 7067 7068 /* get the point-to-point submatrix */ 7069 if (outValues) { 7070 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7071 } 7072 } 7073 else { 7074 newPoints[2 * newP] = b; 7075 newPoints[2 * newP + 1] = o; 7076 newP++; 7077 } 7078 } 7079 } 7080 7081 if (outValues) { 7082 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7083 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7084 /* multiply constraints on the right */ 7085 if (numFields) { 7086 for (f = 0; f < numFields; f++) { 7087 PetscInt oldOff = offsets[f]; 7088 7089 for (p = 0; p < numPoints; p++) { 7090 PetscInt cStart = newPointOffsets[f][p]; 7091 PetscInt b = points[2 * p]; 7092 PetscInt c, r, k; 7093 PetscInt dof; 7094 7095 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7096 if (!dof) { 7097 continue; 7098 } 7099 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7100 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7101 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7102 7103 for (r = 0; r < numIndices; r++) { 7104 for (c = 0; c < nCols; c++) { 7105 for (k = 0; k < dof; k++) { 7106 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7107 } 7108 } 7109 } 7110 } 7111 else { 7112 /* copy this column as is */ 7113 for (r = 0; r < numIndices; r++) { 7114 for (c = 0; c < dof; c++) { 7115 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7116 } 7117 } 7118 } 7119 oldOff += dof; 7120 } 7121 } 7122 } 7123 else { 7124 PetscInt oldOff = 0; 7125 for (p = 0; p < numPoints; p++) { 7126 PetscInt cStart = newPointOffsets[0][p]; 7127 PetscInt b = points[2 * p]; 7128 PetscInt c, r, k; 7129 PetscInt dof; 7130 7131 PetscCall(PetscSectionGetDof(section,b,&dof)); 7132 if (!dof) { 7133 continue; 7134 } 7135 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7136 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7137 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7138 7139 for (r = 0; r < numIndices; r++) { 7140 for (c = 0; c < nCols; c++) { 7141 for (k = 0; k < dof; k++) { 7142 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7143 } 7144 } 7145 } 7146 } 7147 else { 7148 /* copy this column as is */ 7149 for (r = 0; r < numIndices; r++) { 7150 for (c = 0; c < dof; c++) { 7151 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7152 } 7153 } 7154 } 7155 oldOff += dof; 7156 } 7157 } 7158 7159 if (multiplyLeft) { 7160 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7161 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7162 /* multiply constraints transpose on the left */ 7163 if (numFields) { 7164 for (f = 0; f < numFields; f++) { 7165 PetscInt oldOff = offsets[f]; 7166 7167 for (p = 0; p < numPoints; p++) { 7168 PetscInt rStart = newPointOffsets[f][p]; 7169 PetscInt b = points[2 * p]; 7170 PetscInt c, r, k; 7171 PetscInt dof; 7172 7173 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7174 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7175 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7176 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7177 7178 for (r = 0; r < nRows; r++) { 7179 for (c = 0; c < newNumIndices; c++) { 7180 for (k = 0; k < dof; k++) { 7181 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7182 } 7183 } 7184 } 7185 } 7186 else { 7187 /* copy this row as is */ 7188 for (r = 0; r < dof; r++) { 7189 for (c = 0; c < newNumIndices; c++) { 7190 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7191 } 7192 } 7193 } 7194 oldOff += dof; 7195 } 7196 } 7197 } 7198 else { 7199 PetscInt oldOff = 0; 7200 7201 for (p = 0; p < numPoints; p++) { 7202 PetscInt rStart = newPointOffsets[0][p]; 7203 PetscInt b = points[2 * p]; 7204 PetscInt c, r, k; 7205 PetscInt dof; 7206 7207 PetscCall(PetscSectionGetDof(section,b,&dof)); 7208 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7209 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7210 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7211 7212 for (r = 0; r < nRows; r++) { 7213 for (c = 0; c < newNumIndices; c++) { 7214 for (k = 0; k < dof; k++) { 7215 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7216 } 7217 } 7218 } 7219 } 7220 else { 7221 /* copy this row as is */ 7222 for (r = 0; r < dof; r++) { 7223 for (c = 0; c < newNumIndices; c++) { 7224 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7225 } 7226 } 7227 } 7228 oldOff += dof; 7229 } 7230 } 7231 7232 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7233 } 7234 else { 7235 newValues = tmpValues; 7236 } 7237 } 7238 7239 /* clean up */ 7240 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7241 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7242 7243 if (numFields) { 7244 for (f = 0; f < numFields; f++) { 7245 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7246 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7247 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7248 } 7249 } 7250 else { 7251 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7252 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7253 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7254 } 7255 PetscCall(ISRestoreIndices(aIS,&anchors)); 7256 7257 /* output */ 7258 if (outPoints) { 7259 *outPoints = newPoints; 7260 } 7261 else { 7262 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7263 } 7264 if (outValues) { 7265 *outValues = newValues; 7266 } 7267 for (f = 0; f <= numFields; f++) { 7268 offsets[f] = newOffsets[f]; 7269 } 7270 PetscFunctionReturn(0); 7271 } 7272 7273 /*@C 7274 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7275 7276 Not collective 7277 7278 Input Parameters: 7279 + dm - The DM 7280 . section - The PetscSection describing the points (a local section) 7281 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7282 . point - The point defining the closure 7283 - useClPerm - Use the closure point permutation if available 7284 7285 Output Parameters: 7286 + numIndices - The number of dof indices in the closure of point with the input sections 7287 . indices - The dof indices 7288 . outOffsets - Array to write the field offsets into, or NULL 7289 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7290 7291 Notes: 7292 Must call DMPlexRestoreClosureIndices() to free allocated memory 7293 7294 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7295 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7296 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7297 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7298 indices (with the above semantics) are implied. 7299 7300 Level: advanced 7301 7302 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7303 @*/ 7304 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7305 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7306 { 7307 /* Closure ordering */ 7308 PetscSection clSection; 7309 IS clPoints; 7310 const PetscInt *clp; 7311 PetscInt *points; 7312 const PetscInt *clperm = NULL; 7313 /* Dof permutation and sign flips */ 7314 const PetscInt **perms[32] = {NULL}; 7315 const PetscScalar **flips[32] = {NULL}; 7316 PetscScalar *valCopy = NULL; 7317 /* Hanging node constraints */ 7318 PetscInt *pointsC = NULL; 7319 PetscScalar *valuesC = NULL; 7320 PetscInt NclC, NiC; 7321 7322 PetscInt *idx; 7323 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7324 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7325 7326 PetscFunctionBeginHot; 7327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7328 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7329 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7330 if (numIndices) PetscValidIntPointer(numIndices, 6); 7331 if (indices) PetscValidPointer(indices, 7); 7332 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7333 if (values) PetscValidPointer(values, 9); 7334 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7335 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7336 PetscCall(PetscArrayzero(offsets, 32)); 7337 /* 1) Get points in closure */ 7338 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7339 if (useClPerm) { 7340 PetscInt depth, clsize; 7341 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7342 for (clsize=0,p=0; p<Ncl; p++) { 7343 PetscInt dof; 7344 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7345 clsize += dof; 7346 } 7347 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7348 } 7349 /* 2) Get number of indices on these points and field offsets from section */ 7350 for (p = 0; p < Ncl*2; p += 2) { 7351 PetscInt dof, fdof; 7352 7353 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7354 for (f = 0; f < Nf; ++f) { 7355 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7356 offsets[f+1] += fdof; 7357 } 7358 Ni += dof; 7359 } 7360 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7361 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7362 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7363 for (f = 0; f < PetscMax(1, Nf); ++f) { 7364 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7365 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7366 /* may need to apply sign changes to the element matrix */ 7367 if (values && flips[f]) { 7368 PetscInt foffset = offsets[f]; 7369 7370 for (p = 0; p < Ncl; ++p) { 7371 PetscInt pnt = points[2*p], fdof; 7372 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7373 7374 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7375 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7376 if (flip) { 7377 PetscInt i, j, k; 7378 7379 if (!valCopy) { 7380 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7381 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7382 *values = valCopy; 7383 } 7384 for (i = 0; i < fdof; ++i) { 7385 PetscScalar fval = flip[i]; 7386 7387 for (k = 0; k < Ni; ++k) { 7388 valCopy[Ni * (foffset + i) + k] *= fval; 7389 valCopy[Ni * k + (foffset + i)] *= fval; 7390 } 7391 } 7392 } 7393 foffset += fdof; 7394 } 7395 } 7396 } 7397 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7398 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7399 if (NclC) { 7400 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7401 for (f = 0; f < PetscMax(1, Nf); ++f) { 7402 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7403 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7404 } 7405 for (f = 0; f < PetscMax(1, Nf); ++f) { 7406 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7407 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7408 } 7409 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7410 Ncl = NclC; 7411 Ni = NiC; 7412 points = pointsC; 7413 if (values) *values = valuesC; 7414 } 7415 /* 5) Calculate indices */ 7416 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7417 if (Nf) { 7418 PetscInt idxOff; 7419 PetscBool useFieldOffsets; 7420 7421 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7422 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7423 if (useFieldOffsets) { 7424 for (p = 0; p < Ncl; ++p) { 7425 const PetscInt pnt = points[p*2]; 7426 7427 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7428 } 7429 } else { 7430 for (p = 0; p < Ncl; ++p) { 7431 const PetscInt pnt = points[p*2]; 7432 7433 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7434 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7435 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7436 * global section. */ 7437 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7438 } 7439 } 7440 } else { 7441 PetscInt off = 0, idxOff; 7442 7443 for (p = 0; p < Ncl; ++p) { 7444 const PetscInt pnt = points[p*2]; 7445 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7446 7447 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7448 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7449 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7450 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7451 } 7452 } 7453 /* 6) Cleanup */ 7454 for (f = 0; f < PetscMax(1, Nf); ++f) { 7455 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7456 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7457 } 7458 if (NclC) { 7459 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7460 } else { 7461 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7462 } 7463 7464 if (numIndices) *numIndices = Ni; 7465 if (indices) *indices = idx; 7466 PetscFunctionReturn(0); 7467 } 7468 7469 /*@C 7470 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7471 7472 Not collective 7473 7474 Input Parameters: 7475 + dm - The DM 7476 . section - The PetscSection describing the points (a local section) 7477 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7478 . point - The point defining the closure 7479 - useClPerm - Use the closure point permutation if available 7480 7481 Output Parameters: 7482 + numIndices - The number of dof indices in the closure of point with the input sections 7483 . indices - The dof indices 7484 . outOffsets - Array to write the field offsets into, or NULL 7485 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7486 7487 Notes: 7488 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7489 7490 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7491 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7492 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7493 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7494 indices (with the above semantics) are implied. 7495 7496 Level: advanced 7497 7498 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7499 @*/ 7500 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7501 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7502 { 7503 PetscFunctionBegin; 7504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7505 PetscValidPointer(indices, 7); 7506 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7507 PetscFunctionReturn(0); 7508 } 7509 7510 /*@C 7511 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7512 7513 Not collective 7514 7515 Input Parameters: 7516 + dm - The DM 7517 . section - The section describing the layout in v, or NULL to use the default section 7518 . globalSection - The section describing the layout in v, or NULL to use the default global section 7519 . A - The matrix 7520 . point - The point in the DM 7521 . values - The array of values 7522 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7523 7524 Fortran Notes: 7525 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7526 7527 Level: intermediate 7528 7529 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7530 @*/ 7531 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7532 { 7533 DM_Plex *mesh = (DM_Plex*) dm->data; 7534 PetscInt *indices; 7535 PetscInt numIndices; 7536 const PetscScalar *valuesOrig = values; 7537 PetscErrorCode ierr; 7538 7539 PetscFunctionBegin; 7540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7541 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7542 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7543 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7544 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7545 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7546 7547 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7548 7549 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7550 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7551 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7552 if (ierr) { 7553 PetscMPIInt rank; 7554 7555 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7556 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7557 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7558 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7559 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7560 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7561 } 7562 if (mesh->printFEM > 1) { 7563 PetscInt i; 7564 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7565 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7566 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7567 } 7568 7569 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7570 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7571 PetscFunctionReturn(0); 7572 } 7573 7574 /*@C 7575 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7576 7577 Not collective 7578 7579 Input Parameters: 7580 + dmRow - The DM for the row fields 7581 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7582 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7583 . dmCol - The DM for the column fields 7584 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7585 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7586 . A - The matrix 7587 . point - The point in the DMs 7588 . values - The array of values 7589 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7590 7591 Level: intermediate 7592 7593 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7594 @*/ 7595 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7596 { 7597 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7598 PetscInt *indicesRow, *indicesCol; 7599 PetscInt numIndicesRow, numIndicesCol; 7600 const PetscScalar *valuesOrig = values; 7601 PetscErrorCode ierr; 7602 7603 PetscFunctionBegin; 7604 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7605 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7606 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7607 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7608 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7609 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7610 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7611 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7612 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7613 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7614 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7615 7616 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7617 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7618 7619 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7620 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7621 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7622 if (ierr) { 7623 PetscMPIInt rank; 7624 7625 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7626 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7627 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7628 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7629 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7630 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7631 } 7632 7633 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7634 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7635 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7636 PetscFunctionReturn(0); 7637 } 7638 7639 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7640 { 7641 DM_Plex *mesh = (DM_Plex*) dmf->data; 7642 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7643 PetscInt *cpoints = NULL; 7644 PetscInt *findices, *cindices; 7645 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7646 PetscInt foffsets[32], coffsets[32]; 7647 DMPolytopeType ct; 7648 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7649 PetscErrorCode ierr; 7650 7651 PetscFunctionBegin; 7652 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7653 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7654 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7655 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7656 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7657 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7658 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7659 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7660 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7661 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7662 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7663 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7664 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7665 PetscCall(PetscArrayzero(foffsets, 32)); 7666 PetscCall(PetscArrayzero(coffsets, 32)); 7667 /* Column indices */ 7668 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7669 maxFPoints = numCPoints; 7670 /* Compress out points not in the section */ 7671 /* TODO: Squeeze out points with 0 dof as well */ 7672 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7673 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7674 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7675 cpoints[q*2] = cpoints[p]; 7676 cpoints[q*2+1] = cpoints[p+1]; 7677 ++q; 7678 } 7679 } 7680 numCPoints = q; 7681 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7682 PetscInt fdof; 7683 7684 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7685 if (!dof) continue; 7686 for (f = 0; f < numFields; ++f) { 7687 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7688 coffsets[f+1] += fdof; 7689 } 7690 numCIndices += dof; 7691 } 7692 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7693 /* Row indices */ 7694 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7695 { 7696 DMPlexTransform tr; 7697 DMPolytopeType *rct; 7698 PetscInt *rsize, *rcone, *rornt, Nt; 7699 7700 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7701 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7702 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7703 numSubcells = rsize[Nt-1]; 7704 PetscCall(DMPlexTransformDestroy(&tr)); 7705 } 7706 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7707 for (r = 0, q = 0; r < numSubcells; ++r) { 7708 /* TODO Map from coarse to fine cells */ 7709 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7710 /* Compress out points not in the section */ 7711 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7712 for (p = 0; p < numFPoints*2; p += 2) { 7713 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7714 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7715 if (!dof) continue; 7716 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7717 if (s < q) continue; 7718 ftotpoints[q*2] = fpoints[p]; 7719 ftotpoints[q*2+1] = fpoints[p+1]; 7720 ++q; 7721 } 7722 } 7723 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7724 } 7725 numFPoints = q; 7726 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7727 PetscInt fdof; 7728 7729 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7730 if (!dof) continue; 7731 for (f = 0; f < numFields; ++f) { 7732 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7733 foffsets[f+1] += fdof; 7734 } 7735 numFIndices += dof; 7736 } 7737 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7738 7739 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7740 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7741 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7742 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7743 if (numFields) { 7744 const PetscInt **permsF[32] = {NULL}; 7745 const PetscInt **permsC[32] = {NULL}; 7746 7747 for (f = 0; f < numFields; f++) { 7748 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7749 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7750 } 7751 for (p = 0; p < numFPoints; p++) { 7752 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7753 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7754 } 7755 for (p = 0; p < numCPoints; p++) { 7756 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7757 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7758 } 7759 for (f = 0; f < numFields; f++) { 7760 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7761 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7762 } 7763 } else { 7764 const PetscInt **permsF = NULL; 7765 const PetscInt **permsC = NULL; 7766 7767 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7768 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7769 for (p = 0, off = 0; p < numFPoints; p++) { 7770 const PetscInt *perm = permsF ? permsF[p] : NULL; 7771 7772 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7773 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7774 } 7775 for (p = 0, off = 0; p < numCPoints; p++) { 7776 const PetscInt *perm = permsC ? permsC[p] : NULL; 7777 7778 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7779 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7780 } 7781 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7782 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7783 } 7784 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7785 /* TODO: flips */ 7786 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7787 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7788 if (ierr) { 7789 PetscMPIInt rank; 7790 7791 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7792 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7793 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7794 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7795 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7796 } 7797 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7798 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7799 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7800 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7801 PetscFunctionReturn(0); 7802 } 7803 7804 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7805 { 7806 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7807 PetscInt *cpoints = NULL; 7808 PetscInt foffsets[32], coffsets[32]; 7809 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7810 DMPolytopeType ct; 7811 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7812 7813 PetscFunctionBegin; 7814 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7815 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7816 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7817 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7818 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7819 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7820 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7821 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7822 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7823 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7824 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7825 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7826 PetscCall(PetscArrayzero(foffsets, 32)); 7827 PetscCall(PetscArrayzero(coffsets, 32)); 7828 /* Column indices */ 7829 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7830 maxFPoints = numCPoints; 7831 /* Compress out points not in the section */ 7832 /* TODO: Squeeze out points with 0 dof as well */ 7833 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7834 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7835 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7836 cpoints[q*2] = cpoints[p]; 7837 cpoints[q*2+1] = cpoints[p+1]; 7838 ++q; 7839 } 7840 } 7841 numCPoints = q; 7842 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7843 PetscInt fdof; 7844 7845 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7846 if (!dof) continue; 7847 for (f = 0; f < numFields; ++f) { 7848 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7849 coffsets[f+1] += fdof; 7850 } 7851 numCIndices += dof; 7852 } 7853 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7854 /* Row indices */ 7855 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7856 { 7857 DMPlexTransform tr; 7858 DMPolytopeType *rct; 7859 PetscInt *rsize, *rcone, *rornt, Nt; 7860 7861 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7862 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7863 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7864 numSubcells = rsize[Nt-1]; 7865 PetscCall(DMPlexTransformDestroy(&tr)); 7866 } 7867 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7868 for (r = 0, q = 0; r < numSubcells; ++r) { 7869 /* TODO Map from coarse to fine cells */ 7870 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7871 /* Compress out points not in the section */ 7872 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7873 for (p = 0; p < numFPoints*2; p += 2) { 7874 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7875 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7876 if (!dof) continue; 7877 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7878 if (s < q) continue; 7879 ftotpoints[q*2] = fpoints[p]; 7880 ftotpoints[q*2+1] = fpoints[p+1]; 7881 ++q; 7882 } 7883 } 7884 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7885 } 7886 numFPoints = q; 7887 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7888 PetscInt fdof; 7889 7890 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7891 if (!dof) continue; 7892 for (f = 0; f < numFields; ++f) { 7893 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7894 foffsets[f+1] += fdof; 7895 } 7896 numFIndices += dof; 7897 } 7898 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7899 7900 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7901 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7902 if (numFields) { 7903 const PetscInt **permsF[32] = {NULL}; 7904 const PetscInt **permsC[32] = {NULL}; 7905 7906 for (f = 0; f < numFields; f++) { 7907 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7908 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7909 } 7910 for (p = 0; p < numFPoints; p++) { 7911 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7912 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7913 } 7914 for (p = 0; p < numCPoints; p++) { 7915 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7916 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7917 } 7918 for (f = 0; f < numFields; f++) { 7919 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7920 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7921 } 7922 } else { 7923 const PetscInt **permsF = NULL; 7924 const PetscInt **permsC = NULL; 7925 7926 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7927 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7928 for (p = 0, off = 0; p < numFPoints; p++) { 7929 const PetscInt *perm = permsF ? permsF[p] : NULL; 7930 7931 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7932 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7933 } 7934 for (p = 0, off = 0; p < numCPoints; p++) { 7935 const PetscInt *perm = permsC ? permsC[p] : NULL; 7936 7937 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7938 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7939 } 7940 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7941 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7942 } 7943 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7944 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7945 PetscFunctionReturn(0); 7946 } 7947 7948 /*@C 7949 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7950 7951 Input Parameter: 7952 . dm - The DMPlex object 7953 7954 Output Parameter: 7955 . cellHeight - The height of a cell 7956 7957 Level: developer 7958 7959 .seealso `DMPlexSetVTKCellHeight()` 7960 @*/ 7961 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7962 { 7963 DM_Plex *mesh = (DM_Plex*) dm->data; 7964 7965 PetscFunctionBegin; 7966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7967 PetscValidIntPointer(cellHeight, 2); 7968 *cellHeight = mesh->vtkCellHeight; 7969 PetscFunctionReturn(0); 7970 } 7971 7972 /*@C 7973 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7974 7975 Input Parameters: 7976 + dm - The DMPlex object 7977 - cellHeight - The height of a cell 7978 7979 Level: developer 7980 7981 .seealso `DMPlexGetVTKCellHeight()` 7982 @*/ 7983 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7984 { 7985 DM_Plex *mesh = (DM_Plex*) dm->data; 7986 7987 PetscFunctionBegin; 7988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7989 mesh->vtkCellHeight = cellHeight; 7990 PetscFunctionReturn(0); 7991 } 7992 7993 /*@ 7994 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7995 7996 Input Parameter: 7997 . dm - The DMPlex object 7998 7999 Output Parameters: 8000 + gcStart - The first ghost cell, or NULL 8001 - gcEnd - The upper bound on ghost cells, or NULL 8002 8003 Level: advanced 8004 8005 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8006 @*/ 8007 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8008 { 8009 DMLabel ctLabel; 8010 8011 PetscFunctionBegin; 8012 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8013 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8014 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8015 PetscFunctionReturn(0); 8016 } 8017 8018 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8019 { 8020 PetscSection section, globalSection; 8021 PetscInt *numbers, p; 8022 8023 PetscFunctionBegin; 8024 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8025 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8026 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8027 for (p = pStart; p < pEnd; ++p) { 8028 PetscCall(PetscSectionSetDof(section, p, 1)); 8029 } 8030 PetscCall(PetscSectionSetUp(section)); 8031 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8032 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8033 for (p = pStart; p < pEnd; ++p) { 8034 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8035 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8036 else numbers[p-pStart] += shift; 8037 } 8038 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8039 if (globalSize) { 8040 PetscLayout layout; 8041 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8042 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8043 PetscCall(PetscLayoutDestroy(&layout)); 8044 } 8045 PetscCall(PetscSectionDestroy(§ion)); 8046 PetscCall(PetscSectionDestroy(&globalSection)); 8047 PetscFunctionReturn(0); 8048 } 8049 8050 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8051 { 8052 PetscInt cellHeight, cStart, cEnd; 8053 8054 PetscFunctionBegin; 8055 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8056 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8057 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8058 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8059 PetscFunctionReturn(0); 8060 } 8061 8062 /*@ 8063 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8064 8065 Input Parameter: 8066 . dm - The DMPlex object 8067 8068 Output Parameter: 8069 . globalCellNumbers - Global cell numbers for all cells on this process 8070 8071 Level: developer 8072 8073 .seealso `DMPlexGetVertexNumbering()` 8074 @*/ 8075 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8076 { 8077 DM_Plex *mesh = (DM_Plex*) dm->data; 8078 8079 PetscFunctionBegin; 8080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8081 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8082 *globalCellNumbers = mesh->globalCellNumbers; 8083 PetscFunctionReturn(0); 8084 } 8085 8086 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8087 { 8088 PetscInt vStart, vEnd; 8089 8090 PetscFunctionBegin; 8091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8092 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8093 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8094 PetscFunctionReturn(0); 8095 } 8096 8097 /*@ 8098 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8099 8100 Input Parameter: 8101 . dm - The DMPlex object 8102 8103 Output Parameter: 8104 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8105 8106 Level: developer 8107 8108 .seealso `DMPlexGetCellNumbering()` 8109 @*/ 8110 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8111 { 8112 DM_Plex *mesh = (DM_Plex*) dm->data; 8113 8114 PetscFunctionBegin; 8115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8116 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8117 *globalVertexNumbers = mesh->globalVertexNumbers; 8118 PetscFunctionReturn(0); 8119 } 8120 8121 /*@ 8122 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8123 8124 Input Parameter: 8125 . dm - The DMPlex object 8126 8127 Output Parameter: 8128 . globalPointNumbers - Global numbers for all points on this process 8129 8130 Level: developer 8131 8132 .seealso `DMPlexGetCellNumbering()` 8133 @*/ 8134 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8135 { 8136 IS nums[4]; 8137 PetscInt depths[4], gdepths[4], starts[4]; 8138 PetscInt depth, d, shift = 0; 8139 8140 PetscFunctionBegin; 8141 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8142 PetscCall(DMPlexGetDepth(dm, &depth)); 8143 /* For unstratified meshes use dim instead of depth */ 8144 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8145 for (d = 0; d <= depth; ++d) { 8146 PetscInt end; 8147 8148 depths[d] = depth-d; 8149 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8150 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8151 } 8152 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8153 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8154 for (d = 0; d <= depth; ++d) { 8155 PetscCheck(starts[d] < 0 || depths[d] == gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT,depths[d],gdepths[d]); 8156 } 8157 for (d = 0; d <= depth; ++d) { 8158 PetscInt pStart, pEnd, gsize; 8159 8160 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8161 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8162 shift += gsize; 8163 } 8164 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8165 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8166 PetscFunctionReturn(0); 8167 } 8168 8169 /*@ 8170 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8171 8172 Input Parameter: 8173 . dm - The DMPlex object 8174 8175 Output Parameter: 8176 . ranks - The rank field 8177 8178 Options Database Keys: 8179 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8180 8181 Level: intermediate 8182 8183 .seealso: `DMView()` 8184 @*/ 8185 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8186 { 8187 DM rdm; 8188 PetscFE fe; 8189 PetscScalar *r; 8190 PetscMPIInt rank; 8191 DMPolytopeType ct; 8192 PetscInt dim, cStart, cEnd, c; 8193 PetscBool simplex; 8194 8195 PetscFunctionBeginUser; 8196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8197 PetscValidPointer(ranks, 2); 8198 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8199 PetscCall(DMClone(dm, &rdm)); 8200 PetscCall(DMGetDimension(rdm, &dim)); 8201 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8202 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8203 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8204 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8205 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8206 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8207 PetscCall(PetscFEDestroy(&fe)); 8208 PetscCall(DMCreateDS(rdm)); 8209 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8210 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8211 PetscCall(VecGetArray(*ranks, &r)); 8212 for (c = cStart; c < cEnd; ++c) { 8213 PetscScalar *lr; 8214 8215 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8216 if (lr) *lr = rank; 8217 } 8218 PetscCall(VecRestoreArray(*ranks, &r)); 8219 PetscCall(DMDestroy(&rdm)); 8220 PetscFunctionReturn(0); 8221 } 8222 8223 /*@ 8224 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8225 8226 Input Parameters: 8227 + dm - The DMPlex 8228 - label - The DMLabel 8229 8230 Output Parameter: 8231 . val - The label value field 8232 8233 Options Database Keys: 8234 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8235 8236 Level: intermediate 8237 8238 .seealso: `DMView()` 8239 @*/ 8240 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8241 { 8242 DM rdm; 8243 PetscFE fe; 8244 PetscScalar *v; 8245 PetscInt dim, cStart, cEnd, c; 8246 8247 PetscFunctionBeginUser; 8248 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8249 PetscValidPointer(label, 2); 8250 PetscValidPointer(val, 3); 8251 PetscCall(DMClone(dm, &rdm)); 8252 PetscCall(DMGetDimension(rdm, &dim)); 8253 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8254 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8255 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8256 PetscCall(PetscFEDestroy(&fe)); 8257 PetscCall(DMCreateDS(rdm)); 8258 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8259 PetscCall(DMCreateGlobalVector(rdm, val)); 8260 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8261 PetscCall(VecGetArray(*val, &v)); 8262 for (c = cStart; c < cEnd; ++c) { 8263 PetscScalar *lv; 8264 PetscInt cval; 8265 8266 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8267 PetscCall(DMLabelGetValue(label, c, &cval)); 8268 *lv = cval; 8269 } 8270 PetscCall(VecRestoreArray(*val, &v)); 8271 PetscCall(DMDestroy(&rdm)); 8272 PetscFunctionReturn(0); 8273 } 8274 8275 /*@ 8276 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8277 8278 Input Parameter: 8279 . dm - The DMPlex object 8280 8281 Notes: 8282 This is a useful diagnostic when creating meshes programmatically. 8283 8284 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8285 8286 Level: developer 8287 8288 .seealso: `DMCreate()`, `DMSetFromOptions()` 8289 @*/ 8290 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8291 { 8292 PetscSection coneSection, supportSection; 8293 const PetscInt *cone, *support; 8294 PetscInt coneSize, c, supportSize, s; 8295 PetscInt pStart, pEnd, p, pp, csize, ssize; 8296 PetscBool storagecheck = PETSC_TRUE; 8297 8298 PetscFunctionBegin; 8299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8300 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8301 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8302 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8303 /* Check that point p is found in the support of its cone points, and vice versa */ 8304 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8305 for (p = pStart; p < pEnd; ++p) { 8306 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8307 PetscCall(DMPlexGetCone(dm, p, &cone)); 8308 for (c = 0; c < coneSize; ++c) { 8309 PetscBool dup = PETSC_FALSE; 8310 PetscInt d; 8311 for (d = c-1; d >= 0; --d) { 8312 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8313 } 8314 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8315 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8316 for (s = 0; s < supportSize; ++s) { 8317 if (support[s] == p) break; 8318 } 8319 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8320 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8321 for (s = 0; s < coneSize; ++s) { 8322 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8323 } 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8326 for (s = 0; s < supportSize; ++s) { 8327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8328 } 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8330 PetscCheck(!dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not repeatedly found in support of repeated cone point %" PetscInt_FMT, p, cone[c]); 8331 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8332 } 8333 } 8334 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8335 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8336 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8337 PetscCall(DMPlexGetSupport(dm, p, &support)); 8338 for (s = 0; s < supportSize; ++s) { 8339 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8340 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8341 for (c = 0; c < coneSize; ++c) { 8342 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8343 if (cone[c] != pp) { c = 0; break; } 8344 if (cone[c] == p) break; 8345 } 8346 if (c >= coneSize) { 8347 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8348 for (c = 0; c < supportSize; ++c) { 8349 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8350 } 8351 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8352 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8353 for (c = 0; c < coneSize; ++c) { 8354 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8355 } 8356 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8357 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8358 } 8359 } 8360 } 8361 if (storagecheck) { 8362 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8363 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8364 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8365 } 8366 PetscFunctionReturn(0); 8367 } 8368 8369 /* 8370 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. 8371 */ 8372 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8373 { 8374 DMPolytopeType cct; 8375 PetscInt ptpoints[4]; 8376 const PetscInt *cone, *ccone, *ptcone; 8377 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8378 8379 PetscFunctionBegin; 8380 *unsplit = 0; 8381 switch (ct) { 8382 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8383 ptpoints[npt++] = c; 8384 break; 8385 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8386 PetscCall(DMPlexGetCone(dm, c, &cone)); 8387 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8388 for (cp = 0; cp < coneSize; ++cp) { 8389 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8390 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8391 } 8392 break; 8393 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8394 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8395 PetscCall(DMPlexGetCone(dm, c, &cone)); 8396 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8397 for (cp = 0; cp < coneSize; ++cp) { 8398 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8399 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8400 for (ccp = 0; ccp < cconeSize; ++ccp) { 8401 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8402 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8403 PetscInt p; 8404 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8405 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8406 } 8407 } 8408 } 8409 break; 8410 default: break; 8411 } 8412 for (pt = 0; pt < npt; ++pt) { 8413 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8414 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8415 } 8416 PetscFunctionReturn(0); 8417 } 8418 8419 /*@ 8420 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8421 8422 Input Parameters: 8423 + dm - The DMPlex object 8424 - cellHeight - Normally 0 8425 8426 Notes: 8427 This is a useful diagnostic when creating meshes programmatically. 8428 Currently applicable only to homogeneous simplex or tensor meshes. 8429 8430 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8431 8432 Level: developer 8433 8434 .seealso: `DMCreate()`, `DMSetFromOptions()` 8435 @*/ 8436 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8437 { 8438 DMPlexInterpolatedFlag interp; 8439 DMPolytopeType ct; 8440 PetscInt vStart, vEnd, cStart, cEnd, c; 8441 8442 PetscFunctionBegin; 8443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8444 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8445 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8446 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8447 for (c = cStart; c < cEnd; ++c) { 8448 PetscInt *closure = NULL; 8449 PetscInt coneSize, closureSize, cl, Nv = 0; 8450 8451 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8452 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8453 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8454 if (interp == DMPLEX_INTERPOLATED_FULL) { 8455 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8456 PetscCheck(coneSize == DMPolytopeTypeGetConeSize(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has cone size %" PetscInt_FMT " != %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct)); 8457 } 8458 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8459 for (cl = 0; cl < closureSize*2; cl += 2) { 8460 const PetscInt p = closure[cl]; 8461 if ((p >= vStart) && (p < vEnd)) ++Nv; 8462 } 8463 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8464 /* Special Case: Tensor faces with identified vertices */ 8465 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8466 PetscInt unsplit; 8467 8468 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8469 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8470 } 8471 PetscCheck(Nv == DMPolytopeTypeGetNumVertices(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices != %" PetscInt_FMT, c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct)); 8472 } 8473 PetscFunctionReturn(0); 8474 } 8475 8476 /*@ 8477 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8478 8479 Collective 8480 8481 Input Parameters: 8482 + dm - The DMPlex object 8483 - cellHeight - Normally 0 8484 8485 Notes: 8486 This is a useful diagnostic when creating meshes programmatically. 8487 This routine is only relevant for meshes that are fully interpolated across all ranks. 8488 It will error out if a partially interpolated mesh is given on some rank. 8489 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8490 8491 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8492 8493 Level: developer 8494 8495 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8496 @*/ 8497 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8498 { 8499 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8500 DMPlexInterpolatedFlag interpEnum; 8501 8502 PetscFunctionBegin; 8503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8504 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8505 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8506 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8507 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8508 PetscFunctionReturn(0); 8509 } 8510 8511 PetscCall(DMGetDimension(dm, &dim)); 8512 PetscCall(DMPlexGetDepth(dm, &depth)); 8513 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8514 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8515 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8516 for (c = cStart; c < cEnd; ++c) { 8517 const PetscInt *cone, *ornt, *faceSizes, *faces; 8518 const DMPolytopeType *faceTypes; 8519 DMPolytopeType ct; 8520 PetscInt numFaces, coneSize, f; 8521 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8522 8523 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8524 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8525 if (unsplit) continue; 8526 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8527 PetscCall(DMPlexGetCone(dm, c, &cone)); 8528 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8529 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8530 for (cl = 0; cl < closureSize*2; cl += 2) { 8531 const PetscInt p = closure[cl]; 8532 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8533 } 8534 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8535 PetscCheck(coneSize == numFaces,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " faces but should have %" PetscInt_FMT, c, DMPolytopeTypes[ct], coneSize, numFaces); 8536 for (f = 0; f < numFaces; ++f) { 8537 DMPolytopeType fct; 8538 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8539 8540 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8541 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8542 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8543 const PetscInt p = fclosure[cl]; 8544 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8545 } 8546 PetscCheck(fnumCorners == faceSizes[f],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s has %" PetscInt_FMT " vertices but should have %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, c, DMPolytopeTypes[ct], fnumCorners, faceSizes[f]); 8547 for (v = 0; v < fnumCorners; ++v) { 8548 if (fclosure[v] != faces[fOff+v]) { 8549 PetscInt v1; 8550 8551 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8552 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8553 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8554 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8555 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8556 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " of type %s (cone idx %" PetscInt_FMT ", ornt %" PetscInt_FMT ") of cell %" PetscInt_FMT " of type %s vertex %" PetscInt_FMT ", %" PetscInt_FMT " != %" PetscInt_FMT, cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff+v]); 8557 } 8558 } 8559 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8560 fOff += faceSizes[f]; 8561 } 8562 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8563 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8564 } 8565 } 8566 PetscFunctionReturn(0); 8567 } 8568 8569 /*@ 8570 DMPlexCheckGeometry - Check the geometry of mesh cells 8571 8572 Input Parameter: 8573 . dm - The DMPlex object 8574 8575 Notes: 8576 This is a useful diagnostic when creating meshes programmatically. 8577 8578 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8579 8580 Level: developer 8581 8582 .seealso: `DMCreate()`, `DMSetFromOptions()` 8583 @*/ 8584 PetscErrorCode DMPlexCheckGeometry(DM dm) 8585 { 8586 Vec coordinates; 8587 PetscReal detJ, J[9], refVol = 1.0; 8588 PetscReal vol; 8589 PetscBool periodic; 8590 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8591 8592 PetscFunctionBegin; 8593 PetscCall(DMGetDimension(dm, &dim)); 8594 PetscCall(DMGetCoordinateDim(dm, &dE)); 8595 if (dim != dE) PetscFunctionReturn(0); 8596 PetscCall(DMPlexGetDepth(dm, &depth)); 8597 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8598 for (d = 0; d < dim; ++d) refVol *= 2.0; 8599 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8600 /* Make sure local coordinates are created, because that step is collective */ 8601 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8602 for (c = cStart; c < cEnd; ++c) { 8603 DMPolytopeType ct; 8604 PetscInt unsplit; 8605 PetscBool ignoreZeroVol = PETSC_FALSE; 8606 8607 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8608 switch (ct) { 8609 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8610 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8611 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8612 ignoreZeroVol = PETSC_TRUE; break; 8613 default: break; 8614 } 8615 switch (ct) { 8616 case DM_POLYTOPE_TRI_PRISM: 8617 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8618 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8619 case DM_POLYTOPE_PYRAMID: 8620 continue; 8621 default: break; 8622 } 8623 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8624 if (unsplit) continue; 8625 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8626 PetscCheck(detJ >= -PETSC_SMALL && (detJ > 0.0 || ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double) detJ); 8627 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8628 if (depth > 1 && !periodic) { 8629 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8630 PetscCheck(vol >= -PETSC_SMALL && (vol > 0.0 || ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double) vol); 8631 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8632 } 8633 } 8634 PetscFunctionReturn(0); 8635 } 8636 8637 /*@ 8638 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8639 8640 Collective 8641 8642 Input Parameters: 8643 + dm - The DMPlex object 8644 - pointSF - The Point SF, or NULL for Point SF attached to DM 8645 8646 Notes: 8647 This is mainly intended for debugging/testing purposes. 8648 8649 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8650 8651 Level: developer 8652 8653 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8654 @*/ 8655 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8656 { 8657 PetscInt l, nleaves, nroots, overlap; 8658 const PetscInt *locals; 8659 const PetscSFNode *remotes; 8660 PetscBool distributed; 8661 MPI_Comm comm; 8662 PetscMPIInt rank; 8663 8664 PetscFunctionBegin; 8665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8666 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8667 else pointSF = dm->sf; 8668 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8669 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8670 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8671 { 8672 PetscMPIInt mpiFlag; 8673 8674 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8675 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8676 } 8677 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8678 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8679 if (!distributed) { 8680 PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8681 PetscFunctionReturn(0); 8682 } 8683 PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8684 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8685 8686 /* Check SF graph is compatible with DMPlex chart */ 8687 { 8688 PetscInt pStart, pEnd, maxLeaf; 8689 8690 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8691 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8692 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8693 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8694 } 8695 8696 /* Check Point SF has no local points referenced */ 8697 for (l = 0; l < nleaves; l++) { 8698 PetscAssert(remotes[l].rank != (PetscInt) rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 8699 } 8700 8701 /* Check there are no cells in interface */ 8702 if (!overlap) { 8703 PetscInt cellHeight, cStart, cEnd; 8704 8705 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8706 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8707 for (l = 0; l < nleaves; ++l) { 8708 const PetscInt point = locals ? locals[l] : l; 8709 8710 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8711 } 8712 } 8713 8714 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8715 { 8716 const PetscInt *rootdegree; 8717 8718 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8719 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8720 for (l = 0; l < nleaves; ++l) { 8721 const PetscInt point = locals ? locals[l] : l; 8722 const PetscInt *cone; 8723 PetscInt coneSize, c, idx; 8724 8725 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8726 PetscCall(DMPlexGetCone(dm, point, &cone)); 8727 for (c = 0; c < coneSize; ++c) { 8728 if (!rootdegree[cone[c]]) { 8729 if (locals) { 8730 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8731 } else { 8732 idx = (cone[c] < nleaves) ? cone[c] : -1; 8733 } 8734 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8735 } 8736 } 8737 } 8738 } 8739 PetscFunctionReturn(0); 8740 } 8741 8742 /*@ 8743 DMPlexCheck - Perform various checks of Plex sanity 8744 8745 Input Parameter: 8746 . dm - The DMPlex object 8747 8748 Notes: 8749 This is a useful diagnostic when creating meshes programmatically. 8750 8751 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8752 8753 Currently does not include DMPlexCheckCellShape(). 8754 8755 Level: developer 8756 8757 .seealso: DMCreate(), DMSetFromOptions() 8758 @*/ 8759 PetscErrorCode DMPlexCheck(DM dm) 8760 { 8761 PetscInt cellHeight; 8762 8763 PetscFunctionBegin; 8764 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8765 PetscCall(DMPlexCheckSymmetry(dm)); 8766 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8767 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8768 PetscCall(DMPlexCheckGeometry(dm)); 8769 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8770 PetscCall(DMPlexCheckInterfaceCones(dm)); 8771 PetscFunctionReturn(0); 8772 } 8773 8774 typedef struct cell_stats 8775 { 8776 PetscReal min, max, sum, squaresum; 8777 PetscInt count; 8778 } cell_stats_t; 8779 8780 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8781 { 8782 PetscInt i, N = *len; 8783 8784 for (i = 0; i < N; i++) { 8785 cell_stats_t *A = (cell_stats_t *) a; 8786 cell_stats_t *B = (cell_stats_t *) b; 8787 8788 B->min = PetscMin(A->min,B->min); 8789 B->max = PetscMax(A->max,B->max); 8790 B->sum += A->sum; 8791 B->squaresum += A->squaresum; 8792 B->count += A->count; 8793 } 8794 } 8795 8796 /*@ 8797 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8798 8799 Collective on dm 8800 8801 Input Parameters: 8802 + dm - The DMPlex object 8803 . output - If true, statistics will be displayed on stdout 8804 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8805 8806 Notes: 8807 This is mainly intended for debugging/testing purposes. 8808 8809 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8810 8811 Level: developer 8812 8813 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8814 @*/ 8815 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8816 { 8817 DM dmCoarse; 8818 cell_stats_t stats, globalStats; 8819 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8820 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8821 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8822 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8823 PetscMPIInt rank,size; 8824 8825 PetscFunctionBegin; 8826 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8827 stats.min = PETSC_MAX_REAL; 8828 stats.max = PETSC_MIN_REAL; 8829 stats.sum = stats.squaresum = 0.; 8830 stats.count = 0; 8831 8832 PetscCallMPI(MPI_Comm_size(comm, &size)); 8833 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8834 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8835 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8836 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8837 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8838 for (c = cStart; c < cEnd; c++) { 8839 PetscInt i; 8840 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8841 8842 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8843 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8844 for (i = 0; i < PetscSqr(cdim); ++i) { 8845 frobJ += J[i] * J[i]; 8846 frobInvJ += invJ[i] * invJ[i]; 8847 } 8848 cond2 = frobJ * frobInvJ; 8849 cond = PetscSqrtReal(cond2); 8850 8851 stats.min = PetscMin(stats.min,cond); 8852 stats.max = PetscMax(stats.max,cond); 8853 stats.sum += cond; 8854 stats.squaresum += cond2; 8855 stats.count++; 8856 if (output && cond > limit) { 8857 PetscSection coordSection; 8858 Vec coordsLocal; 8859 PetscScalar *coords = NULL; 8860 PetscInt Nv, d, clSize, cl, *closure = NULL; 8861 8862 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8863 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8864 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8865 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8866 for (i = 0; i < Nv/cdim; ++i) { 8867 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8868 for (d = 0; d < cdim; ++d) { 8869 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8870 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8871 } 8872 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8873 } 8874 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8875 for (cl = 0; cl < clSize*2; cl += 2) { 8876 const PetscInt edge = closure[cl]; 8877 8878 if ((edge >= eStart) && (edge < eEnd)) { 8879 PetscReal len; 8880 8881 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8882 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8883 } 8884 } 8885 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8886 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8887 } 8888 } 8889 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8890 8891 if (size > 1) { 8892 PetscMPIInt blockLengths[2] = {4,1}; 8893 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8894 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8895 MPI_Op statReduce; 8896 8897 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8898 PetscCallMPI(MPI_Type_commit(&statType)); 8899 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8900 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8901 PetscCallMPI(MPI_Op_free(&statReduce)); 8902 PetscCallMPI(MPI_Type_free(&statType)); 8903 } else { 8904 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8905 } 8906 if (rank == 0) { 8907 count = globalStats.count; 8908 min = globalStats.min; 8909 max = globalStats.max; 8910 mean = globalStats.sum / globalStats.count; 8911 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8912 } 8913 8914 if (output) { 8915 PetscCall(PetscPrintf(comm,"Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev)); 8916 } 8917 PetscCall(PetscFree2(J,invJ)); 8918 8919 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8920 if (dmCoarse) { 8921 PetscBool isplex; 8922 8923 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8924 if (isplex) { 8925 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8926 } 8927 } 8928 PetscFunctionReturn(0); 8929 } 8930 8931 /*@ 8932 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8933 orthogonal quality below given tolerance. 8934 8935 Collective on dm 8936 8937 Input Parameters: 8938 + dm - The DMPlex object 8939 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8940 - atol - [0, 1] Absolute tolerance for tagging cells. 8941 8942 Output Parameters: 8943 + OrthQual - Vec containing orthogonal quality per cell 8944 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8945 8946 Options Database Keys: 8947 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8948 supported. 8949 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8950 8951 Notes: 8952 Orthogonal quality is given by the following formula: 8953 8954 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8955 8956 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 8957 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8958 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8959 calculating the cosine of the angle between these vectors. 8960 8961 Orthogonal quality ranges from 1 (best) to 0 (worst). 8962 8963 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8964 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8965 8966 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8967 8968 Level: intermediate 8969 8970 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8971 @*/ 8972 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8973 { 8974 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8975 PetscInt *idx; 8976 PetscScalar *oqVals; 8977 const PetscScalar *cellGeomArr, *faceGeomArr; 8978 PetscReal *ci, *fi, *Ai; 8979 MPI_Comm comm; 8980 Vec cellgeom, facegeom; 8981 DM dmFace, dmCell; 8982 IS glob; 8983 ISLocalToGlobalMapping ltog; 8984 PetscViewer vwr; 8985 8986 PetscFunctionBegin; 8987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8988 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8989 PetscValidPointer(OrthQual, 4); 8990 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8991 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8992 PetscCall(DMGetDimension(dm, &nc)); 8993 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8994 { 8995 DMPlexInterpolatedFlag interpFlag; 8996 8997 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8998 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8999 PetscMPIInt rank; 9000 9001 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9002 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9003 } 9004 } 9005 if (OrthQualLabel) { 9006 PetscValidPointer(OrthQualLabel, 5); 9007 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9008 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9009 } else {*OrthQualLabel = NULL;} 9010 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9011 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9012 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9013 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9014 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9015 PetscCall(VecCreate(comm, OrthQual)); 9016 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9017 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9018 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9019 PetscCall(VecSetUp(*OrthQual)); 9020 PetscCall(ISDestroy(&glob)); 9021 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9022 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9023 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9024 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9025 PetscCall(VecGetDM(cellgeom, &dmCell)); 9026 PetscCall(VecGetDM(facegeom, &dmFace)); 9027 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9028 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9029 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9030 PetscInt cellarr[2], *adj = NULL; 9031 PetscScalar *cArr, *fArr; 9032 PetscReal minvalc = 1.0, minvalf = 1.0; 9033 PetscFVCellGeom *cg; 9034 9035 idx[cellIter] = cell-cStart; 9036 cellarr[0] = cell; 9037 /* Make indexing into cellGeom easier */ 9038 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9039 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9040 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9041 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9042 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9043 PetscInt i; 9044 const PetscInt neigh = adj[cellneigh]; 9045 PetscReal normci = 0, normfi = 0, normai = 0; 9046 PetscFVCellGeom *cgneigh; 9047 PetscFVFaceGeom *fg; 9048 9049 /* Don't count ourselves in the neighbor list */ 9050 if (neigh == cell) continue; 9051 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9052 cellarr[1] = neigh; 9053 { 9054 PetscInt numcovpts; 9055 const PetscInt *covpts; 9056 9057 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9058 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9059 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9060 } 9061 9062 /* Compute c_i, f_i and their norms */ 9063 for (i = 0; i < nc; i++) { 9064 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9065 fi[i] = fg->centroid[i] - cg->centroid[i]; 9066 Ai[i] = fg->normal[i]; 9067 normci += PetscPowReal(ci[i], 2); 9068 normfi += PetscPowReal(fi[i], 2); 9069 normai += PetscPowReal(Ai[i], 2); 9070 } 9071 normci = PetscSqrtReal(normci); 9072 normfi = PetscSqrtReal(normfi); 9073 normai = PetscSqrtReal(normai); 9074 9075 /* Normalize and compute for each face-cell-normal pair */ 9076 for (i = 0; i < nc; i++) { 9077 ci[i] = ci[i]/normci; 9078 fi[i] = fi[i]/normfi; 9079 Ai[i] = Ai[i]/normai; 9080 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9081 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9082 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9083 } 9084 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9085 minvalc = PetscRealPart(cArr[cellneighiter]); 9086 } 9087 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9088 minvalf = PetscRealPart(fArr[cellneighiter]); 9089 } 9090 } 9091 PetscCall(PetscFree(adj)); 9092 PetscCall(PetscFree2(cArr, fArr)); 9093 /* Defer to cell if they're equal */ 9094 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9095 if (OrthQualLabel) { 9096 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9097 } 9098 } 9099 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9100 PetscCall(VecAssemblyBegin(*OrthQual)); 9101 PetscCall(VecAssemblyEnd(*OrthQual)); 9102 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9103 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9104 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9105 if (OrthQualLabel) { 9106 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9107 } 9108 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9109 PetscCall(PetscViewerDestroy(&vwr)); 9110 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9111 PetscFunctionReturn(0); 9112 } 9113 9114 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9115 * interpolator construction */ 9116 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9117 { 9118 PetscSection section, newSection, gsection; 9119 PetscSF sf; 9120 PetscBool hasConstraints, ghasConstraints; 9121 9122 PetscFunctionBegin; 9123 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9124 PetscValidPointer(odm,2); 9125 PetscCall(DMGetLocalSection(dm, §ion)); 9126 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9127 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9128 if (!ghasConstraints) { 9129 PetscCall(PetscObjectReference((PetscObject)dm)); 9130 *odm = dm; 9131 PetscFunctionReturn(0); 9132 } 9133 PetscCall(DMClone(dm, odm)); 9134 PetscCall(DMCopyFields(dm, *odm)); 9135 PetscCall(DMGetLocalSection(*odm, &newSection)); 9136 PetscCall(DMGetPointSF(*odm, &sf)); 9137 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9138 PetscCall(DMSetGlobalSection(*odm, gsection)); 9139 PetscCall(PetscSectionDestroy(&gsection)); 9140 PetscFunctionReturn(0); 9141 } 9142 9143 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9144 { 9145 DM dmco, dmfo; 9146 Mat interpo; 9147 Vec rscale; 9148 Vec cglobalo, clocal; 9149 Vec fglobal, fglobalo, flocal; 9150 PetscBool regular; 9151 9152 PetscFunctionBegin; 9153 PetscCall(DMGetFullDM(dmc, &dmco)); 9154 PetscCall(DMGetFullDM(dmf, &dmfo)); 9155 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9156 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9157 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9158 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9159 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9160 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9161 PetscCall(VecSet(cglobalo, 0.)); 9162 PetscCall(VecSet(clocal, 0.)); 9163 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9164 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9165 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9166 PetscCall(VecSet(fglobal, 0.)); 9167 PetscCall(VecSet(fglobalo, 0.)); 9168 PetscCall(VecSet(flocal, 0.)); 9169 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9170 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9171 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9172 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9173 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9174 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9175 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9176 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9177 *shift = fglobal; 9178 PetscCall(VecDestroy(&flocal)); 9179 PetscCall(VecDestroy(&fglobalo)); 9180 PetscCall(VecDestroy(&clocal)); 9181 PetscCall(VecDestroy(&cglobalo)); 9182 PetscCall(VecDestroy(&rscale)); 9183 PetscCall(MatDestroy(&interpo)); 9184 PetscCall(DMDestroy(&dmfo)); 9185 PetscCall(DMDestroy(&dmco)); 9186 PetscFunctionReturn(0); 9187 } 9188 9189 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9190 { 9191 PetscObject shifto; 9192 Vec shift; 9193 9194 PetscFunctionBegin; 9195 if (!interp) { 9196 Vec rscale; 9197 9198 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9199 PetscCall(VecDestroy(&rscale)); 9200 } else { 9201 PetscCall(PetscObjectReference((PetscObject)interp)); 9202 } 9203 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9204 if (!shifto) { 9205 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9206 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9207 shifto = (PetscObject) shift; 9208 PetscCall(VecDestroy(&shift)); 9209 } 9210 shift = (Vec) shifto; 9211 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9212 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9213 PetscCall(MatDestroy(&interp)); 9214 PetscFunctionReturn(0); 9215 } 9216 9217 /* Pointwise interpolation 9218 Just code FEM for now 9219 u^f = I u^c 9220 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9221 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9222 I_{ij} = psi^f_i phi^c_j 9223 */ 9224 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9225 { 9226 PetscSection gsc, gsf; 9227 PetscInt m, n; 9228 void *ctx; 9229 DM cdm; 9230 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9231 9232 PetscFunctionBegin; 9233 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9234 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9235 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9236 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9237 9238 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9239 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9240 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9241 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9242 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9243 9244 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9245 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9246 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9247 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9248 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9249 if (scaling) { 9250 /* Use naive scaling */ 9251 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9252 } 9253 PetscFunctionReturn(0); 9254 } 9255 9256 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9257 { 9258 VecScatter ctx; 9259 9260 PetscFunctionBegin; 9261 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9262 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9263 PetscCall(VecScatterDestroy(&ctx)); 9264 PetscFunctionReturn(0); 9265 } 9266 9267 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9268 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9269 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9270 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9271 { 9272 const PetscInt Nc = uOff[1] - uOff[0]; 9273 PetscInt c; 9274 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9275 } 9276 9277 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9278 { 9279 DM dmc; 9280 PetscDS ds; 9281 Vec ones, locmass; 9282 IS cellIS; 9283 PetscFormKey key; 9284 PetscInt depth; 9285 9286 PetscFunctionBegin; 9287 PetscCall(DMClone(dm, &dmc)); 9288 PetscCall(DMCopyDisc(dm, dmc)); 9289 PetscCall(DMGetDS(dmc, &ds)); 9290 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9291 PetscCall(DMCreateGlobalVector(dmc, mass)); 9292 PetscCall(DMGetLocalVector(dmc, &ones)); 9293 PetscCall(DMGetLocalVector(dmc, &locmass)); 9294 PetscCall(DMPlexGetDepth(dmc, &depth)); 9295 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9296 PetscCall(VecSet(locmass, 0.0)); 9297 PetscCall(VecSet(ones, 1.0)); 9298 key.label = NULL; 9299 key.value = 0; 9300 key.field = 0; 9301 key.part = 0; 9302 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9303 PetscCall(ISDestroy(&cellIS)); 9304 PetscCall(VecSet(*mass, 0.0)); 9305 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9306 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9307 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9308 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9309 PetscCall(DMDestroy(&dmc)); 9310 PetscFunctionReturn(0); 9311 } 9312 9313 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9314 { 9315 PetscSection gsc, gsf; 9316 PetscInt m, n; 9317 void *ctx; 9318 DM cdm; 9319 PetscBool regular; 9320 9321 PetscFunctionBegin; 9322 if (dmFine == dmCoarse) { 9323 DM dmc; 9324 PetscDS ds; 9325 PetscWeakForm wf; 9326 Vec u; 9327 IS cellIS; 9328 PetscFormKey key; 9329 PetscInt depth; 9330 9331 PetscCall(DMClone(dmFine, &dmc)); 9332 PetscCall(DMCopyDisc(dmFine, dmc)); 9333 PetscCall(DMGetDS(dmc, &ds)); 9334 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9335 PetscCall(PetscWeakFormClear(wf)); 9336 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9337 PetscCall(DMCreateMatrix(dmc, mass)); 9338 PetscCall(DMGetGlobalVector(dmc, &u)); 9339 PetscCall(DMPlexGetDepth(dmc, &depth)); 9340 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9341 PetscCall(MatZeroEntries(*mass)); 9342 key.label = NULL; 9343 key.value = 0; 9344 key.field = 0; 9345 key.part = 0; 9346 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9347 PetscCall(ISDestroy(&cellIS)); 9348 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9349 PetscCall(DMDestroy(&dmc)); 9350 } else { 9351 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9352 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9353 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9354 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9355 9356 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9357 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9358 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9359 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9360 9361 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9362 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9363 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9364 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9365 } 9366 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9367 PetscFunctionReturn(0); 9368 } 9369 9370 /*@ 9371 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9372 9373 Input Parameter: 9374 . dm - The DMPlex object 9375 9376 Output Parameter: 9377 . regular - The flag 9378 9379 Level: intermediate 9380 9381 .seealso: `DMPlexSetRegularRefinement()` 9382 @*/ 9383 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9384 { 9385 PetscFunctionBegin; 9386 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9387 PetscValidBoolPointer(regular, 2); 9388 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9389 PetscFunctionReturn(0); 9390 } 9391 9392 /*@ 9393 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9394 9395 Input Parameters: 9396 + dm - The DMPlex object 9397 - regular - The flag 9398 9399 Level: intermediate 9400 9401 .seealso: `DMPlexGetRegularRefinement()` 9402 @*/ 9403 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9404 { 9405 PetscFunctionBegin; 9406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9407 ((DM_Plex *) dm->data)->regularRefinement = regular; 9408 PetscFunctionReturn(0); 9409 } 9410 9411 /* anchors */ 9412 /*@ 9413 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9414 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9415 9416 not collective 9417 9418 Input Parameter: 9419 . dm - The DMPlex object 9420 9421 Output Parameters: 9422 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9423 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9424 9425 Level: intermediate 9426 9427 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9428 @*/ 9429 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9430 { 9431 DM_Plex *plex = (DM_Plex *)dm->data; 9432 9433 PetscFunctionBegin; 9434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9435 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9436 if (anchorSection) *anchorSection = plex->anchorSection; 9437 if (anchorIS) *anchorIS = plex->anchorIS; 9438 PetscFunctionReturn(0); 9439 } 9440 9441 /*@ 9442 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9443 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9444 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9445 9446 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9447 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9448 9449 collective on dm 9450 9451 Input Parameters: 9452 + dm - The DMPlex object 9453 . 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). 9454 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9455 9456 The reference counts of anchorSection and anchorIS are incremented. 9457 9458 Level: intermediate 9459 9460 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9461 @*/ 9462 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9463 { 9464 DM_Plex *plex = (DM_Plex *)dm->data; 9465 PetscMPIInt result; 9466 9467 PetscFunctionBegin; 9468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9469 if (anchorSection) { 9470 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9471 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9472 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9473 } 9474 if (anchorIS) { 9475 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9476 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9477 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9478 } 9479 9480 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9481 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9482 plex->anchorSection = anchorSection; 9483 9484 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9485 PetscCall(ISDestroy(&plex->anchorIS)); 9486 plex->anchorIS = anchorIS; 9487 9488 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9489 PetscInt size, a, pStart, pEnd; 9490 const PetscInt *anchors; 9491 9492 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9493 PetscCall(ISGetLocalSize(anchorIS,&size)); 9494 PetscCall(ISGetIndices(anchorIS,&anchors)); 9495 for (a = 0; a < size; a++) { 9496 PetscInt p; 9497 9498 p = anchors[a]; 9499 if (p >= pStart && p < pEnd) { 9500 PetscInt dof; 9501 9502 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9503 if (dof) { 9504 9505 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9506 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9507 } 9508 } 9509 } 9510 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9511 } 9512 /* reset the generic constraints */ 9513 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9514 PetscFunctionReturn(0); 9515 } 9516 9517 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9518 { 9519 PetscSection anchorSection; 9520 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9521 9522 PetscFunctionBegin; 9523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9524 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9525 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9526 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9527 if (numFields) { 9528 PetscInt f; 9529 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9530 9531 for (f = 0; f < numFields; f++) { 9532 PetscInt numComp; 9533 9534 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9535 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9536 } 9537 } 9538 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9539 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9540 pStart = PetscMax(pStart,sStart); 9541 pEnd = PetscMin(pEnd,sEnd); 9542 pEnd = PetscMax(pStart,pEnd); 9543 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9544 for (p = pStart; p < pEnd; p++) { 9545 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9546 if (dof) { 9547 PetscCall(PetscSectionGetDof(section,p,&dof)); 9548 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9549 for (f = 0; f < numFields; f++) { 9550 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9551 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9552 } 9553 } 9554 } 9555 PetscCall(PetscSectionSetUp(*cSec)); 9556 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9557 PetscFunctionReturn(0); 9558 } 9559 9560 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9561 { 9562 PetscSection aSec; 9563 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9564 const PetscInt *anchors; 9565 PetscInt numFields, f; 9566 IS aIS; 9567 MatType mtype; 9568 PetscBool iscuda,iskokkos; 9569 9570 PetscFunctionBegin; 9571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9572 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9573 PetscCall(PetscSectionGetStorageSize(section, &n)); 9574 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9575 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9576 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9577 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9578 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9579 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9580 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9581 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9582 else mtype = MATSEQAIJ; 9583 PetscCall(MatSetType(*cMat,mtype)); 9584 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9585 PetscCall(ISGetIndices(aIS,&anchors)); 9586 /* cSec will be a subset of aSec and section */ 9587 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9588 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9589 PetscCall(PetscMalloc1(m+1,&i)); 9590 i[0] = 0; 9591 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9592 for (p = pStart; p < pEnd; p++) { 9593 PetscInt rDof, rOff, r; 9594 9595 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9596 if (!rDof) continue; 9597 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9598 if (numFields) { 9599 for (f = 0; f < numFields; f++) { 9600 annz = 0; 9601 for (r = 0; r < rDof; r++) { 9602 a = anchors[rOff + r]; 9603 if (a < sStart || a >= sEnd) continue; 9604 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9605 annz += aDof; 9606 } 9607 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9608 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9609 for (q = 0; q < dof; q++) { 9610 i[off + q + 1] = i[off + q] + annz; 9611 } 9612 } 9613 } else { 9614 annz = 0; 9615 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9616 for (q = 0; q < dof; q++) { 9617 a = anchors[rOff + q]; 9618 if (a < sStart || a >= sEnd) continue; 9619 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9620 annz += aDof; 9621 } 9622 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9623 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9624 for (q = 0; q < dof; q++) { 9625 i[off + q + 1] = i[off + q] + annz; 9626 } 9627 } 9628 } 9629 nnz = i[m]; 9630 PetscCall(PetscMalloc1(nnz,&j)); 9631 offset = 0; 9632 for (p = pStart; p < pEnd; p++) { 9633 if (numFields) { 9634 for (f = 0; f < numFields; f++) { 9635 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9636 for (q = 0; q < dof; q++) { 9637 PetscInt rDof, rOff, r; 9638 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9639 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9640 for (r = 0; r < rDof; r++) { 9641 PetscInt s; 9642 9643 a = anchors[rOff + r]; 9644 if (a < sStart || a >= sEnd) continue; 9645 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9646 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9647 for (s = 0; s < aDof; s++) { 9648 j[offset++] = aOff + s; 9649 } 9650 } 9651 } 9652 } 9653 } else { 9654 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9655 for (q = 0; q < dof; q++) { 9656 PetscInt rDof, rOff, r; 9657 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9658 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9659 for (r = 0; r < rDof; r++) { 9660 PetscInt s; 9661 9662 a = anchors[rOff + r]; 9663 if (a < sStart || a >= sEnd) continue; 9664 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9665 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9666 for (s = 0; s < aDof; s++) { 9667 j[offset++] = aOff + s; 9668 } 9669 } 9670 } 9671 } 9672 } 9673 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9674 PetscCall(PetscFree(i)); 9675 PetscCall(PetscFree(j)); 9676 PetscCall(ISRestoreIndices(aIS,&anchors)); 9677 PetscFunctionReturn(0); 9678 } 9679 9680 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9681 { 9682 DM_Plex *plex = (DM_Plex *)dm->data; 9683 PetscSection anchorSection, section, cSec; 9684 Mat cMat; 9685 9686 PetscFunctionBegin; 9687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9688 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9689 if (anchorSection) { 9690 PetscInt Nf; 9691 9692 PetscCall(DMGetLocalSection(dm,§ion)); 9693 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9694 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9695 PetscCall(DMGetNumFields(dm,&Nf)); 9696 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9697 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9698 PetscCall(PetscSectionDestroy(&cSec)); 9699 PetscCall(MatDestroy(&cMat)); 9700 } 9701 PetscFunctionReturn(0); 9702 } 9703 9704 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9705 { 9706 IS subis; 9707 PetscSection section, subsection; 9708 9709 PetscFunctionBegin; 9710 PetscCall(DMGetLocalSection(dm, §ion)); 9711 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9712 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9713 /* Create subdomain */ 9714 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9715 /* Create submodel */ 9716 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9717 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9718 PetscCall(DMSetLocalSection(*subdm, subsection)); 9719 PetscCall(PetscSectionDestroy(&subsection)); 9720 PetscCall(DMCopyDisc(dm, *subdm)); 9721 /* Create map from submodel to global model */ 9722 if (is) { 9723 PetscSection sectionGlobal, subsectionGlobal; 9724 IS spIS; 9725 const PetscInt *spmap; 9726 PetscInt *subIndices; 9727 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9728 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9729 9730 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9731 PetscCall(ISGetIndices(spIS, &spmap)); 9732 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9733 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9734 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9735 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9736 for (p = pStart; p < pEnd; ++p) { 9737 PetscInt gdof, pSubSize = 0; 9738 9739 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9740 if (gdof > 0) { 9741 for (f = 0; f < Nf; ++f) { 9742 PetscInt fdof, fcdof; 9743 9744 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9745 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9746 pSubSize += fdof-fcdof; 9747 } 9748 subSize += pSubSize; 9749 if (pSubSize) { 9750 if (bs < 0) { 9751 bs = pSubSize; 9752 } else if (bs != pSubSize) { 9753 /* Layout does not admit a pointwise block size */ 9754 bs = 1; 9755 } 9756 } 9757 } 9758 } 9759 /* Must have same blocksize on all procs (some might have no points) */ 9760 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9761 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9762 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9763 else {bs = bsMinMax[0];} 9764 PetscCall(PetscMalloc1(subSize, &subIndices)); 9765 for (p = pStart; p < pEnd; ++p) { 9766 PetscInt gdof, goff; 9767 9768 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9769 if (gdof > 0) { 9770 const PetscInt point = spmap[p]; 9771 9772 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9773 for (f = 0; f < Nf; ++f) { 9774 PetscInt fdof, fcdof, fc, f2, poff = 0; 9775 9776 /* Can get rid of this loop by storing field information in the global section */ 9777 for (f2 = 0; f2 < f; ++f2) { 9778 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9779 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9780 poff += fdof-fcdof; 9781 } 9782 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9783 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9784 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9785 subIndices[subOff] = goff+poff+fc; 9786 } 9787 } 9788 } 9789 } 9790 PetscCall(ISRestoreIndices(spIS, &spmap)); 9791 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9792 if (bs > 1) { 9793 /* We need to check that the block size does not come from non-contiguous fields */ 9794 PetscInt i, j, set = 1; 9795 for (i = 0; i < subSize; i += bs) { 9796 for (j = 0; j < bs; ++j) { 9797 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9798 } 9799 } 9800 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9801 } 9802 /* Attach nullspace */ 9803 for (f = 0; f < Nf; ++f) { 9804 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9805 if ((*subdm)->nullspaceConstructors[f]) break; 9806 } 9807 if (f < Nf) { 9808 MatNullSpace nullSpace; 9809 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9810 9811 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9812 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9813 } 9814 } 9815 PetscFunctionReturn(0); 9816 } 9817 9818 /*@ 9819 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9820 9821 Input Parameter: 9822 - dm - The DM 9823 9824 Level: developer 9825 9826 Options Database Keys: 9827 . -dm_plex_monitor_throughput - Activate the monitor 9828 9829 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9830 @*/ 9831 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9832 { 9833 #if defined(PETSC_USE_LOG) 9834 PetscStageLog stageLog; 9835 PetscLogEvent event; 9836 PetscLogStage stage; 9837 PetscEventPerfInfo eventInfo; 9838 PetscReal cellRate, flopRate; 9839 PetscInt cStart, cEnd, Nf, N; 9840 const char *name; 9841 #endif 9842 9843 PetscFunctionBegin; 9844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9845 #if defined(PETSC_USE_LOG) 9846 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9847 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9848 PetscCall(DMGetNumFields(dm, &Nf)); 9849 PetscCall(PetscLogGetStageLog(&stageLog)); 9850 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9851 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9852 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9853 N = (cEnd - cStart)*Nf*eventInfo.count; 9854 flopRate = eventInfo.flops/eventInfo.time; 9855 cellRate = N/eventInfo.time; 9856 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double) cellRate, (double) (flopRate/1.e6))); 9857 #else 9858 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9859 #endif 9860 PetscFunctionReturn(0); 9861 } 9862