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